Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fabric

Package Overview
Dependencies
Maintainers
2
Versions
309
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fabric - npm Package Compare versions

Comparing version 6.0.0-beta1 to 6.0.0-beta3

.eslintignore

159

CONTRIBUTING.md

@@ -65,3 +65,3 @@ # 🎉 Contributing to Fabric 🥳

### 🎮 Adding a DEMO
### 🎮 Adding a DEMO (currently not possible)

@@ -71,3 +71,3 @@ Take a look at an existing [demo file][demo_file].\

### ~~`fabricjs.com`~~ (_deprecated_)
### ~~`fabricjs.com`~~ (currently not possible)

@@ -96,13 +96,15 @@ To develop fabric's site you need to clone [`fabricjs.com`][website_repo] in the same parent folder of [`fabric.js`][repo], so that `fabric.js` and `fabricjs.com` are siblings.

- Take a look at [**GOTCHAS**][gotchas]
- Follow [Developing](#-developing-) and read [Testing](#-testing).
- Follow [Developing](#-developing-) and [Testing](#-testing).
### ✅ Guidelines
- **Be patient** \
Sometimes it takes time to get back to you. Someone eventually will. Having a small, concise and super clear change will make maintainers more prone to handle it quickly.
- **Code Style** \
Fabric uses [`prettier`][prettier] to format files and [`eslint`][eslint] for linting (`npm run lint -- --fix`).\
To enjoy a seamless dev experience add the [`Prettier - Code formatter`][prettier_extension] extension via the extensions toolbar in VSCode.
- **⛔ `dist`** \
Commit changes to [source files](src). Don't commit the generated [distribution files](dist).
If that doesn't work, once the PR is ready run `npm run prettier:write` and commit the changes.
Do not reorder imports. Irrelevant changes in a PR that are not created by prettier aren't needed nor welcome.
- **Tests** \
PRs must be backed with relevant tests, follow [TESTING](#-testing).
PRs must be backed with relevant tests, follow [TESTING](#-testing). If you never wrote a test or you find our tests unclear to extend, just ask for help.
- **Docs** \

@@ -116,2 +118,3 @@ Add relevant comments to your code if necessary using [JSDoc 3][jsdoc] and update relevant guides.\

If you want to do more than one thing, create multiple pull requests 💪.
If your bug fix or feature requires a refactor, don't refactor. Commit the bugfix or the feature with the current code structure, let it sink, give some time to surface issues with the change, then when the bug or the feature seem solid, a refactor or code improvement can be tried
- **And there you go!** \

@@ -129,52 +132,59 @@ If you still have questions we're always happy to help.

Test suites use [`QUnit`][qunit] for assertions and [`testem`][testem] for serving
Test suites use [`QUnit`][qunit] for assertions and [`testem`][testem] for serving the browser tests
- `unit` tests: test logic and state
- `visual` tests: test visual outcome against image refs located at `/test/visual/golden`
- `visual` tests: test visual outcome against image refs located at `test/visual/golden`
### Getting Started
- build and watch for changes:
- Build and watch for changes
```bash
npm run build -- -f -w
```
- Run the entire test suite on `chrome` (many tests are skipped on `node`)
```bash
npm test -- -a -c chrome
```
- Handle failing tests
- Fix logic
- If needed, alter tests with **caution**
- Rerun failing tests
- Save time by rerunning failing tests only
- Select failing test files
```bash
npm test -- -c chrome
```
- **OR** launch the browser test suite in _dev mode_ to watch for test changes
```bash
npm test -- -c chrome --dev -l
```
- In case of failing visual tests, there are 2 options to view visual diffs (in order to understand what is wrong)
- Testing in _visual debug mode_ is comfortable when using with `Github Desktop` to view the diffs since refs will be overwritten (rerunning tests will use the overwritten refs so be cautious)
```bash
npm test -- -d -c chrome
```
- Launching the browser test suite
```bash
npm test -- -c chrome --dev -l
```
- Take into account that different environments produce different outputs so it is advised to run both in `chrome` and `node`.
- Committing refs is done **ONLY** with `chrome` output.
- When you are done, rerun the entire test suit to verify all tests pass.
- If you are submitting a PR, visit the PR page on github to see all checks have passed (different platforms and config are covered by the checks).
- Refer to the command docs
```bash
npm test -- -h
```
```bash
### Adding Tests
npm run build -- -f -w
Backing a PR with tests that cover the changes that were made is a **MUST**. Aim to cover 100% of the cases.
```
Add tests to relevant files or add new files when necessary under `test/unit` or `test/visual`.
- run tests:
- [`unit` test example][unit_test]
- [`visual` test example][visual_test]
```bash
If you need to change test config ask for guidance.
npm test -- -a -d
> Running all tests in debug mode (read more in the help section)
npm test -- -s visual --dev -l -c chrome
> Running live visual tests on chrome (navigate to see)
npm test -- --help
> Usage: fabric.js test [options]
> run test suite
Options:
-s, --suite <suite...> test suite to run (choices: "unit", "visual")
-f, --file <file> run a specific test file
--filter <filter> filter tests by name
-a, --all run all tests (default: false)
-d, --debug debug visual tests by overriding refs (golden images) in case of visual changes (default:
false)
-r, --recreate recreate visual refs (golden images) (default: false)
-v, --verbose log passing tests (default: false)
-l, --launch launch tests in the browser (default: false)
--dev runs testem in `dev` mode, without a `ci` flag (default: false)
-c, --context <context...> context to test in (choices: "chrome", "firefox", "node", default: "node")
-p, --port
-o, --out <out> path to report test results to
--clear-cache clear CLI test cache (default: false)
-h, --help display help for command
```
---

@@ -184,51 +194,33 @@

### Setting Up Locally
### Getting Started
1. 🍴 Fork the repository
1. 💾 Clone your 🍴 to your 💻
1. 🍴 Fork and clone 💾 the repository
1. Install dependencies 🕹️ `npm i --include=dev`
1. Next Up [Prototyping](#-prototyping) & [Testing](#-testing)
#### Online
### Starting an App
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/)
```bash
npm start <template>
npm start -- --help
```
Gitpod will start the [prototyping](#-prototyping) apps and expose them as endpoints.
`A service is available on port ...` popups will show up.
You can deploy an app to codesandbox via the cli or build an app at a path of your choosing:
### 🧭 Prototyping
[`.codesandbox/templates`](.codesandbox/templates) contains templates for **INSTANT** out-of-the-box prototyping **👍 Try it out**
```bash
npm run sandbox build next [/path/to/sandbox]
> building next app at /path/to/sandbox
npm run sandbox start </path/to/sandbox>
> starting dev server
npm run sandbox deploy </path/to/sandbox>
> created codesandbox https://codesandbox.io/s/fgh476
npm run sandbox deploy -- --template node
> created codesandbox https://codesandbox.io/s/fgh476
npm run sandbox deploy <path/to/app>
npm run sandbox build <template> <path/to/app>
npm run sandbox -- --help
```
> Usage: fabric.js sandbox [options] [command]
Refer to [`.codesandbox/README.md`](.codesandbox/README.md) for more information.
> sandbox commands
### Online
Options:
-h, --help display help for command
You can actively develop fabric online using [Github Codespaces][github_codespaces], [Gitpod][gitpod] or CodeSandbox:
Commands:
deploy [options] [path] deploy a sandbox to codesandbox
build <template> [destination] build and start a sandbox
start <path> start a sandbox
help [command] display help for command
- After the Github Codespace has started run `npm start <template>` to start a prototyping app.
- Gitpod will start the prototyping apps and expose them as endpoints available on forwarded ports.
`A service is available on port ...` popups will show up.
- Codesandbox: _available soon_.
```
### 🔮 Symlinking

@@ -240,2 +232,3 @@

1. From the project's folder run `npm link fabric` **OR** `yarn link fabric`.
1. Consider flagging `--save` to avoid confusion regarding what version of fabric is being used by the project.

@@ -266,3 +259,7 @@ See [npm link][npm_link] **OR** [yarn link][yarn_link].\

[testem]: https://github.com/testem/testem
[unit_test]: https://github.com/fabricjs/fabric.js/blob/93dd2dcca705a4b481fbc9982da4952ef5b4ed1d/test/unit/point.js#L227-L237
[visual_test]: https://github.com/fabricjs/fabric.js/blob/93dd2dcca705a4b481fbc9982da4952ef5b4ed1d/test/visual/generic_rendering.js#L44-L67
[github_codespaces]: https://github.com/codespaces/new?hide_repo_select=true&ref=master&repo=712530
[gitpod]: https://gitpod.io/from-referrer/
[npm_link]: https://docs.npmjs.com/cli/v8/commands/npm-link
[yarn_link]: https://yarnpkg.com/cli/link

@@ -1,7 +0,6 @@

import './src/env/node';
import type { Canvas as NodeCanvas, JpegConfig, PngConfig } from 'canvas';
import type { JpegConfig, PngConfig } from 'canvas';
import { Canvas as CanvasBase, StaticCanvas as StaticCanvasBase } from './fabric';
export * from './fabric';
export declare class StaticCanvas extends StaticCanvasBase {
getNodeCanvas(): NodeCanvas;
getNodeCanvas(): import("canvas").Canvas;
createPNGStream(opts?: PngConfig): import("canvas").PNGStream;

@@ -11,3 +10,3 @@ createJPEGStream(opts?: JpegConfig): import("canvas").JPEGStream;

export declare class Canvas extends CanvasBase {
getNodeCanvas(): NodeCanvas;
getNodeCanvas(): import("canvas").Canvas;
createPNGStream(opts?: PngConfig): import("canvas").PNGStream;

@@ -14,0 +13,0 @@ createJPEGStream(opts?: JpegConfig): import("canvas").JPEGStream;

@@ -1,4 +0,4 @@

import { PathData } from '../typedefs';
import type { Canvas } from '../canvas/Canvas';
import { PencilBrush } from './PencilBrush';
import { TSimplePathData } from '../util/path/typedefs';
export declare class PatternBrush extends PencilBrush {

@@ -21,4 +21,4 @@ source?: CanvasImageSource;

*/
createPath(pathData: PathData): import("../..").Path;
createPath(pathData: TSimplePathData): import("../..").Path<Partial<import("../shapes/Path").PathProps>, import("../shapes/Path").SerializedPathProps, import("../EventTypeDefs").ObjectEvents>;
}
//# sourceMappingURL=PatternBrush.d.ts.map
import { ModifierKey, TEvent } from '../EventTypeDefs';
import { Point } from '../Point';
import { Path } from '../shapes/Path';
import { PathData } from '../typedefs';
import type { Canvas } from '../canvas/Canvas';
import { BaseBrush } from './BaseBrush';
import { TSimplePathData } from '../util/path/typedefs';
export declare class PencilBrush extends BaseBrush {

@@ -71,12 +71,12 @@ /**

* Converts points to SVG path
* @param {Array} points Array of points
* @return {PathData} SVG path commands
* @param {Point[]} points Array of points
* @return {TSimplePathData} SVG path commands
*/
convertPointsToSVGPath(points: Point[]): PathData;
convertPointsToSVGPath(points: Point[]): TSimplePathData;
/**
* Creates a Path object to add on canvas
* @param {PathData} pathData Path data
* @param {TSimplePathData} pathData Path data
* @return {Path} Path to add on canvas
*/
createPath(pathData: PathData): Path;
createPath(pathData: TSimplePathData): Path;
/**

@@ -83,0 +83,0 @@ * Decimate points array with the decimate value

@@ -0,1 +1,2 @@

import { TRectBounds } from './typedefs';
export declare class Cache {

@@ -43,5 +44,5 @@ /**

*/
boundsOfCurveCache: {};
boundsOfCurveCache: Record<string, TRectBounds>;
}
export declare const cache: Cache;
//# sourceMappingURL=cache.d.ts.map
import { CanvasEvents, DragEventData, ObjectEvents, TPointerEvent, TPointerEventInfo, TPointerEventNames, Transform } from '../EventTypeDefs';
import { Point } from '../Point';
import { Group } from '../shapes/Group';
import type { IText } from '../shapes/IText/IText';
import type { FabricObject } from '../shapes/Object/FabricObject';
import { AssertKeys } from '../typedefs';
import { SelectableCanvas } from './SelectableCanvas';

@@ -54,9 +56,2 @@ import { TextEditingManager } from './TextEditingManager';

currentSubTargets?: FabricObject[];
/**
* Holds a reference to a pointer during mousedown to compare on mouse up and determine
* if it was a click event
* @type FabricObject
* @private
*/
_previousPointer: Point;
private _isClick;

@@ -121,4 +116,4 @@ textEditingManager: TextEditingManager;

protected findDragTargets(e: DragEvent): {
target: FabricObject<ObjectEvents> | undefined;
targets: FabricObject<ObjectEvents>[];
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
targets: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
};

@@ -222,3 +217,6 @@ /**

'before:render': {
ctx: CanvasRenderingContext2D;
ctx: CanvasRenderingContext2D; /**
* @private
* @param {Event} [e] Event object fired on wheel event
*/
};

@@ -229,4 +227,4 @@ 'after:render': {

} & Record<"mouse:down" | "mouse:down:before" | "mouse:move" | "mouse:move:before" | "mouse:up" | "mouse:up:before" | "mouse:dblclick", TPointerEventInfo<TPointerEvent>> & Record<"mouse:wheel", TPointerEventInfo<WheelEvent>> & Record<"mouse:over", import("../EventTypeDefs").TEvent<TPointerEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
button?: number | undefined;

@@ -237,9 +235,9 @@ isClick: boolean;

absolutePointer: Point;
currentSubTargets?: FabricObject<ObjectEvents>[] | undefined;
currentTarget?: FabricObject<ObjectEvents> | null | undefined;
currentSubTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
currentTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | null | undefined;
} & {
previousTarget?: FabricObject<ObjectEvents> | undefined;
previousTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
}> & Record<"mouse:out", import("../EventTypeDefs").TEvent<TPointerEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
button?: number | undefined;

@@ -250,9 +248,9 @@ isClick: boolean;

absolutePointer: Point;
currentSubTargets?: FabricObject<ObjectEvents>[] | undefined;
currentTarget?: FabricObject<ObjectEvents> | null | undefined;
currentSubTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
currentTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | null | undefined;
} & {
nextTarget?: FabricObject<ObjectEvents> | undefined;
nextTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
}> & {
dragstart: import("../EventTypeDefs").TEvent<DragEvent> & {
target: FabricObject<ObjectEvents>;
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};

@@ -262,20 +260,20 @@ drag: DragEventData;

dragenter: import("../EventTypeDefs").TEvent<DragEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
dragSource?: FabricObject<ObjectEvents> | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
dragSource?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
canDrop?: boolean | undefined;
didDrop?: boolean | undefined;
dropTarget?: FabricObject<ObjectEvents> | undefined;
dropTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
} & {
previousTarget?: FabricObject<ObjectEvents> | undefined;
previousTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
};
dragleave: import("../EventTypeDefs").TEvent<DragEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
dragSource?: FabricObject<ObjectEvents> | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
dragSource?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
canDrop?: boolean | undefined;
didDrop?: boolean | undefined;
dropTarget?: FabricObject<ObjectEvents> | undefined;
dropTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
} & {
nextTarget?: FabricObject<ObjectEvents> | undefined;
nextTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
};

@@ -288,20 +286,20 @@ dragend: DragEventData;

'drag:enter': import("../EventTypeDefs").TEvent<DragEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
dragSource?: FabricObject<ObjectEvents> | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
dragSource?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
canDrop?: boolean | undefined;
didDrop?: boolean | undefined;
dropTarget?: FabricObject<ObjectEvents> | undefined;
dropTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
} & {
previousTarget?: FabricObject<ObjectEvents> | undefined;
previousTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
};
'drag:leave': import("../EventTypeDefs").TEvent<DragEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
dragSource?: FabricObject<ObjectEvents> | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
dragSource?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
canDrop?: boolean | undefined;
didDrop?: boolean | undefined;
dropTarget?: FabricObject<ObjectEvents> | undefined;
dropTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
} & {
nextTarget?: FabricObject<ObjectEvents> | undefined;
nextTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
};

@@ -312,5 +310,5 @@ } & import("../EventTypeDefs").MiscEvents & Record<"object:moving" | "object:scaling" | "object:rotating" | "object:skewing" | "object:resizing", import("../EventTypeDefs").TEvent<TPointerEvent> & {

} & {
target: FabricObject<ObjectEvents>;
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
}> & Record<"object:modified", import("../EventTypeDefs").ModifiedEvent<TPointerEvent> | {
target: FabricObject<ObjectEvents>;
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
}> & {

@@ -322,46 +320,46 @@ 'before:transform': import("../EventTypeDefs").TEvent<TPointerEvent> & {

'selection:created': Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
selected: FabricObject<ObjectEvents>[];
selected: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
};
'selection:updated': Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
selected: FabricObject<ObjectEvents>[];
deselected: FabricObject<ObjectEvents>[];
selected: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
deselected: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
};
'before:selection:cleared': Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
deselected: FabricObject<ObjectEvents>[];
deselected: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
};
'selection:cleared': Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
deselected: FabricObject<ObjectEvents>[];
deselected: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
};
} & {
'before:path:created': {
path: FabricObject<ObjectEvents>;
path: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};
'path:created': {
path: FabricObject<ObjectEvents>;
path: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};
'erasing:start': never;
'erasing:end': {
path: FabricObject<ObjectEvents>;
targets: FabricObject<ObjectEvents>[];
subTargets: FabricObject<ObjectEvents>[];
path: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
targets: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
subTargets: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[];
drawables: {
backgroundImage?: FabricObject<ObjectEvents> | undefined;
overlayImage?: FabricObject<ObjectEvents> | undefined;
backgroundImage?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
overlayImage?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
};
};
'text:selection:changed': {
target: import("../..").IText<import("../shapes/IText/ITextBehavior").ITextEvents>;
target: IText<import("../shapes/IText/IText").ITextProps, import("../shapes/IText/IText").SerializedITextProps, import("../shapes/IText/ITextBehavior").ITextEvents>;
};
'text:changed': {
target: import("../..").IText<import("../shapes/IText/ITextBehavior").ITextEvents>;
target: IText<import("../shapes/IText/IText").ITextProps, import("../shapes/IText/IText").SerializedITextProps, import("../shapes/IText/ITextBehavior").ITextEvents>;
};
'text:editing:entered': {
target: import("../..").IText<import("../shapes/IText/ITextBehavior").ITextEvents>;
target: IText<import("../shapes/IText/IText").ITextProps, import("../shapes/IText/IText").SerializedITextProps, import("../shapes/IText/ITextBehavior").ITextEvents>;
};
'text:editing:exited': {
target: import("../..").IText<import("../shapes/IText/ITextBehavior").ITextEvents>;
target: IText<import("../shapes/IText/IText").ITextProps, import("../shapes/IText/IText").SerializedITextProps, import("../shapes/IText/ITextBehavior").ITextEvents>;
};
} & Record<"mousedown" | "mousedown:before" | "mousemove" | "mousemove:before" | "mouseup" | "mouseup:before" | "mousedblclick", TPointerEventInfo<TPointerEvent>> & Record<"mousewheel", TPointerEventInfo<WheelEvent>> & Record<"mouseover", import("../EventTypeDefs").TEvent<TPointerEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
button?: number | undefined;

@@ -372,9 +370,9 @@ isClick: boolean;

absolutePointer: Point;
currentSubTargets?: FabricObject<ObjectEvents>[] | undefined;
currentTarget?: FabricObject<ObjectEvents> | null | undefined;
currentSubTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
currentTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | null | undefined;
} & {
previousTarget?: FabricObject<ObjectEvents> | undefined;
previousTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
}> & Record<"mouseout", import("../EventTypeDefs").TEvent<TPointerEvent> & {
target?: FabricObject<ObjectEvents> | undefined;
subTargets?: FabricObject<ObjectEvents>[] | undefined;
target?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
subTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
button?: number | undefined;

@@ -385,21 +383,21 @@ isClick: boolean;

absolutePointer: Point;
currentSubTargets?: FabricObject<ObjectEvents>[] | undefined;
currentTarget?: FabricObject<ObjectEvents> | null | undefined;
currentSubTargets?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>[] | undefined;
currentTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | null | undefined;
} & {
nextTarget?: FabricObject<ObjectEvents> | undefined;
nextTarget?: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents> | undefined;
}> & Record<"moving" | "scaling" | "rotating" | "skewing" | "resizing", import("../EventTypeDefs").BasicTransformEvent<TPointerEvent>> & Record<"modified", import("../EventTypeDefs").ModifiedEvent<TPointerEvent>> & {
selected: Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
target: FabricObject<ObjectEvents>;
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};
deselected: Partial<import("../EventTypeDefs").TEvent<TPointerEvent>> & {
target: FabricObject<ObjectEvents>;
target: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};
added: {
target: import("./StaticCanvas").StaticCanvas<import("../EventTypeDefs").StaticCanvasEvents> | Canvas | Group;
target: Canvas | Group | import("./StaticCanvas").StaticCanvas<import("../EventTypeDefs").StaticCanvasEvents>;
};
removed: {
target: import("./StaticCanvas").StaticCanvas<import("../EventTypeDefs").StaticCanvasEvents> | Canvas | Group;
target: Canvas | Group | import("./StaticCanvas").StaticCanvas<import("../EventTypeDefs").StaticCanvasEvents>;
};
'erasing:end': {
path: FabricObject<ObjectEvents>;
path: FabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, ObjectEvents>;
};

@@ -531,39 +529,22 @@ })[T];

/**
* Return true if the current mouse event that generated a new selection should generate a group
* ## Handles multiple selection
* - toggles `target` selection (selects/deselects `target` if it isn't/is selected respectively)
* - sets the active object in case it is not set or in case there is a single active object left under active selection.
* ---
* - If the active object is the active selection we add/remove `target` from it
* - If not, add the active object and `target` to the active selection and make it the active object.
* @private
* @param {TPointerEvent} e Event object
* @param {FabricObject} target
* @return {Boolean}
* @param {FabricObject} target target of event to select/deselect
* @returns true if grouping occurred
*/
_shouldGroup(e: TPointerEvent, target?: FabricObject): boolean;
protected handleMultiSelection(e: TPointerEvent, target?: FabricObject): this is AssertKeys<this, '_activeObject'>;
/**
* Handles active selection creation for user event
* @private
* @param {TPointerEvent} e Event object
* @param {FabricObject} target
* ## Handles selection
* - selects objects that are contained in (and possibly intersecting) the selection bounding box
* - sets the active object
* ---
* runs on mouse up
*/
_handleGrouping(e: TPointerEvent, target: FabricObject): void;
/**
* @private
*/
_updateActiveSelection(e: TPointerEvent, target: FabricObject): void;
/**
* Generates and set as active the active selection from user events
* @private
*/
_createActiveSelection(e: TPointerEvent, target: FabricObject): void;
/**
* Finds objects inside the selection rectangle and group them
* @private
* @param {Event} e mouse event
*/
_groupSelectedObjects(e: TPointerEvent): void;
/**
* @private
*/
_collectObjects(e: TPointerEvent): FabricObject<ObjectEvents>[];
/**
* @private
*/
_maybeGroupObjects(e: TPointerEvent): void;
protected handleSelection(e: TPointerEvent): this is AssertKeys<this, '_activeObject'>;
exitTextEditing(): void;

@@ -570,0 +551,0 @@ /**

@@ -5,12 +5,34 @@ import { Point } from '../Point';

import { StaticCanvas, TCanvasSizeOptions } from './StaticCanvas';
import { TMat2D, TOriginX, TOriginY, TSize } from '../typedefs';
import { AssertKeys, TMat2D, TOriginX, TOriginY, TSize } from '../typedefs';
import type { BaseBrush } from '../brushes/BaseBrush';
import { TSVGReviver } from '../typedefs';
type TDestroyedCanvas = Omit<SelectableCanvas<CanvasEvents>, 'contextTop' | 'contextCache' | 'lowerCanvasEl' | 'upperCanvasEl' | 'cacheCanvasEl' | 'wrapperEl'> & {
wrapperEl?: HTMLDivElement;
cacheCanvasEl?: HTMLCanvasElement;
upperCanvasEl?: HTMLCanvasElement;
lowerCanvasEl?: HTMLCanvasElement;
contextCache?: CanvasRenderingContext2D | null;
contextTop?: CanvasRenderingContext2D | null;
import { ActiveSelection } from '../shapes/ActiveSelection';
export declare const DefaultCanvasProperties: {
uniformScaling: boolean;
uniScaleKey: string;
centeredScaling: boolean;
centeredRotation: boolean;
centeredKey: string;
altActionKey: string;
selection: boolean;
selectionKey: string;
selectionColor: string;
selectionDashArray: never[];
selectionBorderColor: string;
selectionLineWidth: number;
selectionFullyContained: boolean;
hoverCursor: string;
moveCursor: string;
defaultCursor: string;
freeDrawingCursor: string;
notAllowedCursor: string;
containerClass: string;
perPixelTargetFind: boolean;
targetFindTolerance: number;
skipTargetFind: boolean;
preserveObjectStacking: boolean;
stopContextMenu: boolean;
fireRightClick: boolean;
fireMiddleClick: boolean;
enablePointerEvents: boolean;
};

@@ -363,3 +385,3 @@ /**

/**
* hold a reference to a data structure used to track the selecion
* hold a reference to a data structure used to track the selection
* box on canvas drag

@@ -370,3 +392,8 @@ * on the current on going transform

*/
_groupSelector: any;
protected _groupSelector: {
x: number;
y: number;
deltaX: number;
deltaY: number;
} | null;
/**

@@ -380,10 +407,2 @@ * internal flag used to understand if the context top requires a cleanup

/**
* a reference to the context of an additional canvas that is used for scratch operations
* @TODOL This is created automatically when needed, while it shouldn't. is probably not even often needed
* and is a memory waste. We should either have one that gets added/deleted
* @type CanvasRenderingContext2D
* @private
*/
contextCache: CanvasRenderingContext2D;
/**
* During a mouse event we may need the pointer multiple times in multiple functions.

@@ -411,9 +430,14 @@ * _absolutePointer holds a reference to the pointer in fabricCanvas/design coordinates that is valid for the event

protected _target?: FabricObject;
static ownDefaults: Record<string, any>;
static getDefaults(): Record<string, any>;
upperCanvasEl: HTMLCanvasElement;
contextTop: CanvasRenderingContext2D;
wrapperEl: HTMLDivElement;
cacheCanvasEl: HTMLCanvasElement;
private pixelFindCanvasEl;
private pixelFindContext;
protected _isCurrentlyDrawing: boolean;
freeDrawingBrush?: BaseBrush;
_activeObject?: FabricObject;
protected readonly _activeSelection: ActiveSelection;
constructor(el: string | HTMLCanvasElement, options?: {});
protected initElements(el: string | HTMLCanvasElement): void;

@@ -453,3 +477,3 @@ protected _initRetinaScaling(): void;

* Given a pointer on the canvas with a viewport applied,
* find out the opinter in
* find out the pointer in object coordinates
* @private

@@ -459,2 +483,8 @@ */

/**
* Set the canvas tolerance value for pixel taret find.
* Use only integer numbers.
* @private
*/
setTargetFindTolerance(value: number): void;
/**
* Returns true if object is transparent at a certain location

@@ -481,3 +511,3 @@ * Clarification: this is `is target transparent at location X or are controls there`

*/
_shouldClearSelection(e: TPointerEvent, target?: FabricObject): boolean;
_shouldClearSelection(e: TPointerEvent, target?: FabricObject): target is undefined;
/**

@@ -527,10 +557,8 @@ * This method will take in consideration a modifier key pressed and the control we are

* Method that determines what object we are clicking on
* the skipGroup parameter is for internal use, is needed for shift+click action
* 11/09/2018 TODO: would be cool if findTarget could discern between being a full target
* or the outside part of the corner.
* @param {Event} e mouse event
* @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through
* @return {FabricObject | null} the target found
*/
findTarget(e: TPointerEvent, skipGroup?: boolean): FabricObject | undefined;
findTarget(e: TPointerEvent): FabricObject | undefined;
/**

@@ -639,2 +667,6 @@ * Checks point is inside the object.

/**
* Returns instance's active selection
*/
getActiveSelection(): ActiveSelection;
/**
* Returns an array with the current selected objects

@@ -655,18 +687,15 @@ * @return {FabricObject[]} active objects array

* @param {TPointerEvent} [e] Event (passed along when firing "object:selected")
* @chainable
* @return {Boolean} true if the object has been selected
*/
setActiveObject(object: FabricObject, e?: TPointerEvent): void;
setActiveObject(object: FabricObject, e?: TPointerEvent): this is AssertKeys<this, '_activeObject'>;
/**
* This is a private method for now.
* This is supposed to be equivalent to setActiveObject but without firing
* any event. There is commitment to have this stay this way.
* This is the functional part of setActiveObject.
* @private
* @param {Object} object to set as active
* @param {Event} [e] Event (passed along when firing "object:selected")
* @return {Boolean} true if the selection happened
* @return {Boolean} true if the object has been selected
*/
_setActiveObject(object: FabricObject, e?: TPointerEvent): boolean;
_setActiveObject(object: FabricObject, e?: TPointerEvent): this is AssertKeys<this, '_activeObject'>;
/**
* This is a private method for now.
* This is supposed to be equivalent to discardActiveObject but without firing

@@ -677,6 +706,7 @@ * any selection events ( can still fire object transformation events ). There is commitment to have this stay this way.

* @param {Object} object the next object to set as active, reason why we are discarding this
* @return {Boolean} true if the selection happened
* @private
* @return {Boolean} true if the active object has been discarded
*/
_discardActiveObject(e?: TPointerEvent, object?: FabricObject): boolean;
_discardActiveObject(e?: TPointerEvent, object?: FabricObject): this is {
_activeObject: undefined;
};
/**

@@ -688,5 +718,7 @@ * Discards currently active object and fire events. If the function is called by fabric

* @param {event} e
* @chainable
* @return {Boolean} true if the active object has been discarded
*/
discardActiveObject(e?: TPointerEvent): void;
discardActiveObject(e?: TPointerEvent): this is {
_activeObject: undefined;
};
/**

@@ -709,3 +741,3 @@ * Sets viewport transformation of this canvas instance

*/
destroy(this: TDestroyedCanvas): void;
destroy(): void;
/**

@@ -725,3 +757,3 @@ * Clears all contexts (background, main, top) of an instance

/**
* Realises an object's group transformation on it
* Realizes an object's group transformation on it
* @private

@@ -737,3 +769,2 @@ * @param {FabricObject} [instance] the object to transform (gets mutated)

}
export {};
//# sourceMappingURL=SelectableCanvas.d.ts.map

@@ -8,2 +8,6 @@ import type { CanvasEvents, StaticCanvasEvents } from '../EventTypeDefs';

import { EnlivenObjectOptions } from '../util/misc/objectEnlive';
type TDestroyed<T, K extends keyof any> = {
[R in K | keyof T]: R extends K ? T[R] | undefined | null : T[R];
};
export type TDestroyedCanvas<T extends StaticCanvas> = TDestroyed<T, 'contextTop' | 'pixelFindContext' | 'lowerCanvasEl' | 'upperCanvasEl' | 'pixelFindCanvasEl' | 'wrapperEl' | '_activeSelection'>;
export type TCanvasSizeOptions = {

@@ -29,2 +33,20 @@ backstoreOnly?: boolean;

};
export declare const StaticCanvasDefaults: {
backgroundColor: string;
backgroundImage: null;
overlayColor: string;
overlayImage: null;
includeDefaultValues: boolean;
renderOnAddRemove: boolean;
controlsAboveOverlay: boolean;
allowTouchScrolling: boolean;
imageSmoothingEnabled: boolean;
viewportTransform: number[];
backgroundVpt: boolean;
overlayVpt: boolean;
enableRetinaScaling: boolean;
svgViewportTransformation: boolean;
skipOffscreen: boolean;
clipPath: undefined;
};
declare const StaticCanvas_base: {

@@ -53,2 +75,5 @@ new (...args: any[]): {

findNewUpperIndex(object: FabricObject, idx: number, intersecting?: boolean | undefined): number;
collectObjects({ left, top, width, height }: import("../typedefs").TBBox, { includeIntersecting }?: {
includeIntersecting?: boolean | undefined;
}): import("../shapes/Object/InteractiveObject").InteractiveFabricObject<Partial<import("../shapes/Object/types").FabricObjectProps>, import("../shapes/Object/types").SerializedObjectProps, import("../EventTypeDefs").ObjectEvents>[];
};

@@ -237,2 +262,3 @@ } & {

protected nextRenderHandle: number;
static ownDefaults: Record<string, any>;
protected __cleanupTask?: {

@@ -242,2 +268,3 @@ (): void;

};
static getDefaults(): Record<string, any>;
constructor(el: string | HTMLCanvasElement, options?: {});

@@ -550,3 +577,3 @@ protected initElements(el: string | HTMLCanvasElement): void;

*/
_toObject(instance: FabricObject, methodName: TValidToObjectMethod, propertiesToInclude?: string[]): Record<string, any>;
_toObject(instance: FabricObject, methodName: TValidToObjectMethod, propertiesToInclude?: string[]): any;
/**

@@ -553,0 +580,0 @@ * @private

@@ -1,3 +0,4 @@

import type { Constructor } from './typedefs';
import type { Constructor, TBBox } from './typedefs';
import type { BaseFabricObject } from './EventTypeDefs';
import { InteractiveFabricObject } from './shapes/Object/InteractiveObject';
export declare function createCollectionMixin<TBase extends Constructor>(Base: TBase): {

@@ -124,4 +125,13 @@ new (...args: any[]): {

findNewUpperIndex(object: BaseFabricObject, idx: number, intersecting?: boolean): number;
/**
* Given a bounding box, return all the objects of the collection that are contained in the bounding box.
* If `includeIntersecting` is true, return also the objects that intersect the bounding box as well.
* This is meant to work with selection. Is not a generic method.
* @returns array of objects contained in the bounding box, ordered from top to bottom stacking wise
*/
collectObjects({ left, top, width, height }: TBBox, { includeIntersecting }?: {
includeIntersecting?: boolean | undefined;
}): InteractiveFabricObject<Partial<import("./shapes/Object/types").FabricObjectProps>, import("./shapes/Object/types").SerializedObjectProps, import("./EventTypeDefs").ObjectEvents>[];
};
} & TBase;
//# sourceMappingURL=Collection.d.ts.map
import { ControlActionHandler, TPointerEvent, TransformActionHandler } from '../EventTypeDefs';
import { Point } from '../Point';
import type { FabricObject } from '../shapes/Object/Object';
import type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';
import { TDegree, TMat2D } from '../typedefs';
import { ControlRenderingStyleOverride } from './controls.render';
import { ControlRenderingStyleOverride } from './controlRendering';
export declare class Control {

@@ -149,3 +149,3 @@ /**

*/
getActionHandler(eventData: TPointerEvent, fabricObject: FabricObject, control: Control): TransformActionHandler | undefined;
getActionHandler(eventData: TPointerEvent, fabricObject: InteractiveFabricObject, control: Control): TransformActionHandler | undefined;
/**

@@ -158,3 +158,3 @@ * Returns control mouseDown handler

*/
getMouseDownHandler(eventData: TPointerEvent, fabricObject: FabricObject, control: Control): ControlActionHandler | undefined;
getMouseDownHandler(eventData: TPointerEvent, fabricObject: InteractiveFabricObject, control: Control): ControlActionHandler | undefined;
/**

@@ -168,3 +168,3 @@ * Returns control mouseUp handler.

*/
getMouseUpHandler(eventData: TPointerEvent, fabricObject: FabricObject, control: Control): ControlActionHandler | undefined;
getMouseUpHandler(eventData: TPointerEvent, fabricObject: InteractiveFabricObject, control: Control): ControlActionHandler | undefined;
/**

@@ -179,3 +179,3 @@ * Returns control cursorStyle for css using cursorStyle. If you need a more elaborate

*/
cursorStyleHandler(eventData: TPointerEvent, control: Control, fabricObject: FabricObject): string;
cursorStyleHandler(eventData: TPointerEvent, control: Control, fabricObject: InteractiveFabricObject): string;
/**

@@ -188,3 +188,3 @@ * Returns the action name. The basic implementation just return the actionName property.

*/
getActionName(eventData: TPointerEvent, control: Control, fabricObject: FabricObject): string;
getActionName(eventData: TPointerEvent, control: Control, fabricObject: InteractiveFabricObject): string;
/**

@@ -196,3 +196,3 @@ * Returns controls visibility

*/
getVisibility(fabricObject: FabricObject, controlKey: string): any;
getVisibility(fabricObject: InteractiveFabricObject, controlKey: string): boolean;
/**

@@ -203,4 +203,4 @@ * Sets controls visibility

*/
setVisibility(visibility: boolean, name: string, fabricObject: FabricObject): void;
positionHandler(dim: Point, finalMatrix: TMat2D, fabricObject: FabricObject, currentControl: Control): Point;
setVisibility(visibility: boolean, name: string, fabricObject: InteractiveFabricObject): void;
positionHandler(dim: Point, finalMatrix: TMat2D, fabricObject: InteractiveFabricObject, currentControl: Control): Point;
/**

@@ -233,4 +233,4 @@ * Returns the coords for this control based on object values.

*/
render(ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride | undefined, fabricObject: FabricObject): void;
render(ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride | undefined, fabricObject: InteractiveFabricObject): void;
}
//# sourceMappingURL=Control.d.ts.map

@@ -0,7 +1,15 @@

/**
* This file is consumed by fabric.
* The `./node` and `./browser` files define the env variable that is used by this module.
* The `./node` module sets the env at import time.
* The `./browser` module is defined to be the default env and doesn't set the env at all.
* This is done in order to support isomorphic usage for browser and node applications
* since window and document aren't defined at time of import in SSR, we can't set env so we avoid it by deferring to the default env.
*/
import { TFabricEnv } from './types';
import type { DOMWindow } from 'jsdom';
export declare const setEnv: (value: TFabricEnv) => void;
export declare const getEnv: () => TFabricEnv;
export declare const getDocument: () => Document;
export declare const getWindow: () => Window;
export declare const setEnvForTests: (window: Window) => void;
export declare const getWindow: () => Window | DOMWindow;
//# sourceMappingURL=index.d.ts.map

@@ -0,3 +1,5 @@

import type { Canvas as NodeCanvas } from 'canvas';
import { TFabricEnv } from './types';
export declare const getNodeCanvas: (canvasEl: HTMLCanvasElement) => NodeCanvas;
export declare const getEnv: () => TFabricEnv;
//# sourceMappingURL=node.d.ts.map

@@ -1,2 +0,3 @@

import type { Canvas } from 'canvas';
import { GLProbe } from '../filters/GLProbes/GLProbe';
import type { DOMWindow } from 'jsdom';
export type TCopyPasteData = {

@@ -8,9 +9,8 @@ copiedText?: string;

document: Document;
window: Window;
window: Window | DOMWindow;
isTouchSupported: boolean;
isLikelyNode: boolean;
nodeCanvas?: Canvas;
jsdomImplForWrapper?: any;
WebGLProbe: GLProbe;
dispose(element: Element): void;
copyPasteData: TCopyPasteData;
};
//# sourceMappingURL=types.d.ts.map

@@ -60,2 +60,3 @@ import type { Control } from './controls/Control';

};
reset?: boolean;
actionPerformed: boolean;

@@ -62,0 +63,0 @@ };

import type { T2DPipelineState, TWebGLAttributeLocationMap, TWebGLPipelineState, TWebGLProgramCacheItem, TWebGLUniformLocationMap } from './typedefs';
export type AbstractBaseFilterOptions<T> = {
mainParameter: string;
vertexSource: string;
fragmentSource: T;
};
export type BaseFilterOptions = AbstractBaseFilterOptions<string>;
export interface AnyFilter extends AbstractBaseFilter<string | Record<string, string>> {
}
export declare abstract class AbstractBaseFilter<T> {
export declare class BaseFilter {
/**

@@ -16,3 +8,4 @@ * Filter type

*/
type: string;
get type(): string;
static defaults: Record<string, any>;
/**

@@ -23,3 +16,2 @@ * Array of attributes to send with buffers. do not modify

vertexSource: string;
fragmentSource: T;
/**

@@ -31,3 +23,3 @@ * Name of the parameter that can be changed in the filter.

*/
mainParameter?: keyof this;
mainParameter?: keyof this | undefined;
/**

@@ -37,4 +29,4 @@ * Constructor

*/
constructor(options?: Partial<AbstractBaseFilterOptions<T>> & Record<string, any>);
abstract getFragmentSource(): string;
constructor({ ...options }?: Record<string, any>);
protected getFragmentSource(): string;
/**

@@ -69,3 +61,3 @@ * Compile this filter's shader program.

*/
abstract getUniformLocations(gl: WebGLRenderingContext, program: WebGLProgram): TWebGLUniformLocationMap;
getUniformLocations(gl: WebGLRenderingContext, program: WebGLProgram): TWebGLUniformLocationMap;
/**

@@ -102,3 +94,8 @@ * Send attribute data from this filter to its shader program on the GPU.

applyTo(options: TWebGLPipelineState | T2DPipelineState): void;
abstract applyTo2d(options: T2DPipelineState): void;
applyTo2d(options: T2DPipelineState): void;
/**
* Returns a string that represent the current selected shader code for the filter.
* Used to force recompilation when parameters change or to retrieve the shader from cache
* @type string
**/
getCacheKey(): string;

@@ -138,3 +135,3 @@ /**

*/
abstract sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
/**

@@ -159,6 +156,6 @@ * If needed by a 2d filter, this functions can create an helper canvas to be used

};
static fromObject({ type, ...filterOptions }: Record<string, any>, options: {
signal: AbortSignal;
}): Promise<BaseFilter>;
}
export declare abstract class BaseFilter extends AbstractBaseFilter<string> {
getFragmentSource(): string;
}
//# sourceMappingURL=BaseFilter.d.ts.map
import { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
type TBlendMode = 'multiply' | 'add' | 'difference' | 'screen' | 'subtract' | 'darken' | 'lighten' | 'overlay' | 'exclusion' | 'tint';
export declare const blendColorDefaultValues: Partial<TClassProperties<BlendColor>>;
/**

@@ -21,3 +23,3 @@ * Color Blend filter class

*/
export declare class BlendColor extends AbstractBaseFilter<Record<string, string>> {
export declare class BlendColor extends BaseFilter {
/**

@@ -30,4 +32,10 @@ * Color to make the blend operation with. default to a reddish color since black or white

color: string;
mode: 'multiply' | 'add' | 'diff' | 'difference' | 'screen' | 'subtract' | 'darken' | 'lighten' | 'overlay' | 'exclusion' | 'tint';
/**
* Blend mode for the filter: one of multiply, add, difference, screen, subtract,
* darken, lighten, overlay, exclusion, tint.
* @type String
* @default
**/
mode: TBlendMode;
/**
* alpha value. represent the strength of the blend color operation.

@@ -38,12 +46,5 @@ * @type Number

alpha: number;
/**
* build the fragment source for the filters, joining the common part with
* the specific one.
* @param {String} mode the mode of the filter, a key of this.fragmentSource
* @return {String} the source to be compiled
* @private
*/
buildSource(mode: string): string;
static defaults: Partial<TClassProperties<BlendColor>>;
getCacheKey(): string;
getFragmentSource(): string;
protected getFragmentSource(): string;
/**

@@ -77,8 +78,7 @@ * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.

color: string;
mode: "darken" | "difference" | "exclusion" | "lighten" | "multiply" | "overlay" | "screen" | "add" | "diff" | "subtract" | "tint";
mode: TBlendMode;
alpha: number;
};
static fromObject(object: any): Promise<BlendColor>;
}
export declare const blendColorDefaultValues: Partial<TClassProperties<BlendColor>>;
export {};
//# sourceMappingURL=BlendColor.d.ts.map
import { Image } from '../shapes/Image';
import type { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { WebGLFilterBackend } from './WebGLFilterBackend';
export type TBlendImageMode = 'multiply' | 'mask';
export declare const blendImageDefaultValues: Partial<TClassProperties<BlendImage>>;
/**

@@ -23,3 +25,3 @@ * Image Blend filter class

*/
export declare class BlendImage extends AbstractBaseFilter<Record<string, string>> {
export declare class BlendImage extends BaseFilter {
/**

@@ -30,3 +32,3 @@ * Color to make the blend operation with. default to a reddish color since black or white

image: Image;
mode: 'multiply' | 'mask';
mode: TBlendImageMode;
/**

@@ -37,2 +39,3 @@ * alpha value. represent the strength of the blend image operation.

alpha: number;
static defaults: Partial<TClassProperties<BlendImage>>;
getCacheKey(): string;

@@ -76,4 +79,4 @@ getFragmentSource(): string;

type: string;
image: Record<string, any>;
mode: "multiply" | "mask";
image: Pick<Omit<Partial<import("../shapes/Image").ImageProps> & TClassProperties<Image<Partial<import("../shapes/Image").ImageProps>, import("../shapes/Image").SerializedImageProps, import("../EventTypeDefs").ObjectEvents>>, keyof import("../shapes/Image").SerializedImageProps>, never> & import("../shapes/Image").SerializedImageProps;
mode: TBlendImageMode;
alpha: number;

@@ -89,7 +92,6 @@ };

*/
static fromObject(object: Record<string, any>, options: {
static fromObject({ type, image, ...filterOptions }: Record<string, any>, options: {
signal: AbortSignal;
}): Promise<BlendImage>;
}): Promise<BaseFilter>;
}
export declare const blendImageDefaultValues: Partial<TClassProperties<BlendImage>>;
//# sourceMappingURL=BlendImage.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { TWebGLPipelineState, T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const blurDefaultValues: Partial<TClassProperties<Blur>>;
/**

@@ -25,2 +26,4 @@ * Blur filter class

aspectRatio: number;
static defaults: Partial<TClassProperties<Blur>>;
getFragmentSource(): string;
applyTo(options: TWebGLPipelineState | T2DPipelineState): void;

@@ -48,5 +51,3 @@ applyTo2d(options: T2DPipelineState): void;

chooseRightDelta(): number[];
static fromObject(object: any): Promise<Blur>;
}
export declare const blurDefaultValues: Partial<TClassProperties<Blur>>;
//# sourceMappingURL=Blur.d.ts.map
import { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const myFilterDefaultValues: Partial<TClassProperties<MyFilter>>;
/**

@@ -22,2 +23,4 @@ * MyFilter filter class

myParameter: number;
static defaults: Partial<TClassProperties<MyFilter>>;
getFragmentSource(): string;
/**

@@ -44,5 +47,4 @@ * Apply the MyFilter operation to a Uint8ClampedArray representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<MyFilter>;
static fromObject(object: any): Promise<BaseFilter>;
}
export declare const myFilterDefaultValues: Partial<TClassProperties<MyFilter>>;
//# sourceMappingURL=Boilerplate.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const brightnessDefaultValues: Partial<TClassProperties<Brightness>>;
/**

@@ -22,2 +23,4 @@ * Brightness filter class

brightness: number;
static defaults: Partial<TClassProperties<Brightness>>;
getFragmentSource(): string;
/**

@@ -44,5 +47,3 @@ * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Brightness>;
}
export declare const brightnessDefaultValues: Partial<TClassProperties<Brightness>>;
//# sourceMappingURL=Brightness.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const colorMatrixDefaultValues: Partial<TClassProperties<ColorMatrix>>;
/**

@@ -37,3 +38,5 @@ * Color Matrix filter class

colorsOnly: boolean;
static defaults: Partial<TClassProperties<ColorMatrix>>;
setOptions({ matrix, ...options }: Record<string, any>): void;
getFragmentSource(): string;
/**

@@ -60,5 +63,3 @@ * Apply the ColorMatrix operation to a Uint8Array representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<ColorMatrix>;
}
export declare const colorMatrixDefaultValues: Partial<TClassProperties<ColorMatrix>>;
//# sourceMappingURL=ColorMatrix.d.ts.map

@@ -1,3 +0,2 @@

import type { TClassProperties } from '../typedefs';
import { type AnyFilter, BaseFilter, type BaseFilterOptions } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLPipelineState } from './typedefs';

@@ -11,6 +10,6 @@ /**

*/
subFilters: AnyFilter[];
constructor({ subFilters, ...options }?: Partial<BaseFilterOptions & {
subFilters: AnyFilter[];
}>);
subFilters: BaseFilter[];
constructor({ subFilters, ...options }?: {
subFilters?: BaseFilter[];
} & Record<string, any>);
/**

@@ -45,5 +44,4 @@ * Apply this container's filters to the input image provided.

signal: AbortSignal;
}): Promise<Composed>;
}): Promise<BaseFilter>;
}
export declare const composedDefaultValues: Partial<TClassProperties<Composed>>;
//# sourceMappingURL=Composed.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const contrastDefaultValues: Partial<TClassProperties<Contrast>>;
/**

@@ -20,2 +21,4 @@ * Contrast filter class

contrast: number;
static defaults: Partial<TClassProperties<Contrast>>;
getFragmentSource(): string;
/**

@@ -42,5 +45,3 @@ * Apply the Contrast operation to a Uint8Array representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Contrast>;
}
export declare const contrastDefaultValues: Partial<TClassProperties<Contrast>>;
//# sourceMappingURL=Contrast.d.ts.map
import type { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const convoluteDefaultValues: Partial<TClassProperties<Convolute>>;
/**

@@ -44,6 +45,7 @@ * Adapted from <a href="http://www.html5rocks.com/en/tutorials/canvas/imagefilters/">html5rocks article</a>

*/
export declare class Convolute extends AbstractBaseFilter<Record<string, string>> {
export declare class Convolute extends BaseFilter {
opaque: boolean;
matrix: number[];
getCacheKey(): string;
static defaults: Partial<TClassProperties<Convolute>>;
getCacheKey(): "Convolute_3_1" | "Convolute_3_0" | "Convolute_5_1" | "Convolute_5_0" | "Convolute_7_1" | "Convolute_7_0" | "Convolute_9_1" | "Convolute_9_0";
getFragmentSource(): string;

@@ -80,5 +82,3 @@ /**

};
static fromObject(object: any): Promise<Convolute>;
}
export declare const convoluteDefaultValues: Partial<TClassProperties<Convolute>>;
//# sourceMappingURL=Convolute.d.ts.map

@@ -9,3 +9,3 @@ import { Canvas2dFilterBackend } from './Canvas2dFilterBackend';

/**
* Get the current fabricJS filter backend or initialize one if not avaialble yet
* Get the current fabricJS filter backend or initialize one if not available yet
* @param [strict] pass `true` to create the backend if it wasn't created yet (default behavior),

@@ -12,0 +12,0 @@ * pass `false` to get the backend ref without mutating it

import type { TClassProperties } from '../typedefs';
import { BaseFilter, BaseFilterOptions } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export type GammaInput = [number, number, number];
export declare const gammaDefaultValues: Partial<TClassProperties<Gamma>>;
/**

@@ -26,3 +27,5 @@ * Gamma filter class

};
constructor({ gamma, ...options }?: Partial<BaseFilterOptions> & {
static defaults: Partial<TClassProperties<Gamma>>;
getFragmentSource(): string;
constructor({ gamma, ...options }?: {
gamma?: GammaInput;

@@ -51,5 +54,3 @@ });

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Gamma>;
}
export declare const gammaDefaultValues: Partial<TClassProperties<Gamma>>;
//# sourceMappingURL=Gamma.d.ts.map
import type { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export type TGrayscaleMode = 'average' | 'lightness' | 'luminosity';
export declare const grayscaleDefaultValues: Partial<TClassProperties<Grayscale>>;
/**

@@ -11,4 +13,5 @@ * Grayscale image filter class

*/
export declare class Grayscale extends AbstractBaseFilter<Record<string, string>> {
mode: 'average' | 'lightness' | 'luminosity';
export declare class Grayscale extends BaseFilter {
mode: TGrayscaleMode;
static defaults: Partial<TClassProperties<Grayscale>>;
/**

@@ -43,5 +46,3 @@ * Apply the Grayscale operation to a Uint8Array representing the pixels of an image.

isNeutralState(): boolean;
static fromObject(object: any): Promise<Grayscale>;
}
export declare const grayscaleDefaultValues: Partial<TClassProperties<Grayscale>>;
//# sourceMappingURL=Grayscale.d.ts.map
import type { TClassProperties } from '../typedefs';
import { ColorMatrix } from './ColorMatrix';
import type { TWebGLPipelineState, T2DPipelineState } from './typedefs';
export declare const hueRotationDefaultValues: Partial<TClassProperties<HueRotation>>;
/**

@@ -18,8 +19,7 @@ * HueRotation filter class

rotation: number;
static defaults: Partial<TClassProperties<HueRotation>>;
calculateMatrix(): void;
isNeutralState(): boolean;
applyTo(options: TWebGLPipelineState | T2DPipelineState): void;
static fromObject(object: any): Promise<HueRotation>;
}
export declare const hueRotationDefaultValues: Partial<TClassProperties<HueRotation>>;
//# sourceMappingURL=HueRotation.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const invertDefaultValues: Partial<TClassProperties<Invert>>;
/**

@@ -23,2 +24,3 @@ * @example

invert: boolean;
static defaults: Partial<TClassProperties<Invert>>;
/**

@@ -31,2 +33,3 @@ * Apply the Invert operation to a Uint8Array representing the pixels of an image.

applyTo2d({ imageData: { data } }: T2DPipelineState): void;
protected getFragmentSource(): string;
/**

@@ -53,5 +56,3 @@ * Invert filter isNeutralState implementation

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Invert>;
}
export declare const invertDefaultValues: Partial<TClassProperties<Invert>>;
//# sourceMappingURL=Invert.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const noiseDefaultValues: Partial<TClassProperties<Noise>>;
/**

@@ -21,2 +22,4 @@ * Noise filter class

noise: number;
static defaults: Partial<TClassProperties<Noise>>;
getFragmentSource(): string;
/**

@@ -51,5 +54,3 @@ * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.

};
static fromObject(object: any): Promise<Noise>;
}
export declare const noiseDefaultValues: Partial<TClassProperties<Noise>>;
//# sourceMappingURL=Noise.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const pixelateDefaultValues: Partial<TClassProperties<Pixelate>>;
/**

@@ -15,2 +16,3 @@ * Pixelate filter class

blocksize: number;
static defaults: Partial<TClassProperties<Pixelate>>;
/**

@@ -27,2 +29,3 @@ * Apply the Pixelate operation to a Uint8ClampedArray representing the pixels of an image.

isNeutralState(): boolean;
protected getFragmentSource(): string;
/**

@@ -42,5 +45,3 @@ * Return WebGL uniform locations for this filter's shader.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Pixelate>;
}
export declare const pixelateDefaultValues: Partial<TClassProperties<Pixelate>>;
//# sourceMappingURL=Pixelate.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const removeColorDefaultValues: Partial<TClassProperties<RemoveColor>>;
/**

@@ -31,2 +32,4 @@ * Remove white filter class

useAlpha: boolean;
static defaults: Partial<TClassProperties<RemoveColor>>;
getFragmentShader(): string;
/**

@@ -60,5 +63,3 @@ * Applies filter to canvas element

};
static fromObject(object: any): Promise<RemoveColor>;
}
export declare const removeColorDefaultValues: Partial<TClassProperties<RemoveColor>>;
//# sourceMappingURL=RemoveColor.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLPipelineState } from './typedefs';
export declare const resizeDefaultValues: Partial<TClassProperties<Resize>>;
type TResizeType = 'bilinear' | 'hermite' | 'sliceHack' | 'lanczos';
/**

@@ -18,3 +20,3 @@ * Resize image filter class

*/
resizeType: 'bilinear' | 'hermite' | 'sliceHack' | 'lanczos';
resizeType: TResizeType;
/**

@@ -39,2 +41,3 @@ * Scale factor for resizing, x axis

fragmentSourceTOP: string;
static defaults: Partial<TClassProperties<Resize>>;
/**

@@ -130,8 +133,7 @@ * Return WebGL uniform locations for this filter's shader.

scaleY: number;
resizeType: "bilinear" | "hermite" | "sliceHack" | "lanczos";
resizeType: TResizeType;
lanczosLobes: number;
};
static fromObject(object: any): Promise<Resize>;
}
export declare const resizeDefaultValues: Partial<TClassProperties<Resize>>;
export {};
//# sourceMappingURL=Resize.d.ts.map

@@ -13,2 +13,3 @@ import type { TClassProperties } from '../typedefs';

*/
export declare const saturationDefaultValues: Partial<TClassProperties<Saturation>>;
export declare class Saturation extends BaseFilter {

@@ -24,2 +25,4 @@ /**

saturation: number;
static defaults: Partial<TClassProperties<Saturation>>;
getFragmentSource(): string;
/**

@@ -46,5 +49,3 @@ * Apply the Saturation operation to a Uint8ClampedArray representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Saturation>;
}
export declare const saturationDefaultValues: Partial<TClassProperties<Saturation>>;
//# sourceMappingURL=Saturation.d.ts.map
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
export declare const vibranceDefaultValues: Partial<TClassProperties<Vibrance>>;
/**

@@ -23,2 +24,4 @@ * Vibrance filter class

vibrance: number;
static defaults: Partial<TClassProperties<Vibrance>>;
getFragmentSource(): string;
/**

@@ -45,5 +48,3 @@ * Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.

sendUniformData(gl: WebGLRenderingContext, uniformLocations: TWebGLUniformLocationMap): void;
static fromObject(object: any): Promise<Vibrance>;
}
export declare const vibranceDefaultValues: Partial<TClassProperties<Vibrance>>;
//# sourceMappingURL=Vibrance.d.ts.map

@@ -1,6 +0,3 @@

export declare function parseColorStops(el: SVGGradientElement, opacityAttr: string | null): {
offset: number;
color: string;
opacity: number;
}[];
import { ColorStop } from '../typedefs';
export declare function parseColorStops(el: SVGGradientElement, opacityAttr: string | null): ColorStop[];
//# sourceMappingURL=parseColorStops.d.ts.map

@@ -21,3 +21,15 @@ import { Point } from './Point';

/**
* check if point T is on the segment or line defined between A and B
*
* @param {Point} T the point we are checking for
* @param {Point} A one extremity of the segment
* @param {Point} B the other extremity of the segment
* @param [infinite] if true checks if `T` is on the line defined by `A` and `B`
* @returns true if `T` is contained
*/
static isPointContained(T: Point, A: Point, B: Point, infinite?: boolean): boolean;
/**
* Checks if a line intersects another
* @see {@link https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection line intersection}
* @see {@link https://en.wikipedia.org/wiki/Cramer%27s_rule Cramer's rule}
* @static

@@ -24,0 +36,0 @@ * @param {Point} a1

@@ -38,11 +38,17 @@ export type TEventCallback<T = any> = (options: T) => any;

/**
* Stops event observing for a particular event handler. Calling this method
* without arguments removes all handlers for all events
* @param {string} eventName Event name (eg. 'after:render')
* @param {EventRegistryObject} handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {Function} handler Function to be deleted from EventListeners
* unsubscribe an event listener
* @param {string} eventName event name (eg. 'after:render')
* @param {TEventCallback} handler event listener to unsubscribe
*/
off<K extends keyof EventSpec>(eventName: K, handler: TEventCallback): void;
/**
* unsubscribe event listeners
* @param handlers handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
*/
off(handlers: EventRegistryObject): void;
/**
* unsubscribe all event listeners
*/
off(): void;
/**
* Fires event with an optional options object

@@ -49,0 +55,0 @@ * @param {String} eventName Event name to fire

@@ -11,4 +11,3 @@ export declare const cssRules: {};

export declare const svgNS = "http://www.w3.org/2000/svg";
export declare const commaWsp = "(?:\\s+,?\\s*|,\\s*)";
export declare const rePathCommand: RegExp;
export declare const commaWsp: string;
export declare const reFontDeclaration: RegExp;

@@ -15,0 +14,0 @@ export declare const svgValidTagNames: string[], svgViewBoxElements: string[], svgInvalidAncestors: string[], svgValidParents: string[], attributesMap: {

@@ -5,3 +5,3 @@ /**

*/
export declare function elementById(doc: any, id: any): any;
export declare function elementById(doc: Document, id: string): Element | undefined;
//# sourceMappingURL=elementById.d.ts.map
/**
* @private
*/
export declare function elementMatchesRule(element: any, selectors: any): boolean;
export declare function elementMatchesRule(element: HTMLElement, selectors: string[]): boolean;
//# sourceMappingURL=elementMatchesRule.d.ts.map

@@ -1,2 +0,2 @@

export declare function selectorMatches(element: any, selector: any): boolean;
export declare function selectorMatches(element: HTMLElement, selector: string): boolean;
//# sourceMappingURL=selectorMatches.d.ts.map

@@ -26,4 +26,13 @@ import { TCrossOrigin, TMat2D, TSize } from './typedefs';

export declare class Pattern {
type: string;
/**
* Legacy identifier of the class. Prefer using this.constructor.name 'Pattern'
* or utils like isPattern
* Will be removed in fabric 7 or 8.
* @TODO add sustainable warning message
* @type string
* @deprecated
*/
get type(): string;
set type(value: string);
/**
* @type TPatternRepeat

@@ -30,0 +39,0 @@ * @defaults

import { TMat2D, TRadian } from './typedefs';
export interface IPoint {
export interface XY {
x: number;

@@ -9,3 +9,3 @@ y: number;

*/
export declare class Point implements IPoint {
export declare class Point implements XY {
x: number;

@@ -15,12 +15,12 @@ y: number;

constructor(x: number, y: number);
constructor(point: IPoint);
constructor(point: XY);
/**
* Adds another point to this one and returns another one
* @param {IPoint} that
* @param {XY} that
* @return {Point} new Point instance with added values
*/
add(that: IPoint): Point;
add(that: XY): Point;
/**
* Adds another point to this one
* @param {IPoint} that
* @param {XY} that
* @return {Point} thisArg

@@ -30,3 +30,3 @@ * @chainable

*/
addEquals(that: IPoint): Point;
addEquals(that: XY): Point;
/**

@@ -48,9 +48,9 @@ * Adds value to this point and returns a new one

* Subtracts another point from this point and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point} new Point object with subtracted values
*/
subtract(that: IPoint): Point;
subtract(that: XY): Point;
/**
* Subtracts another point from this point
* @param {IPoint} that
* @param {XY} that
* @return {Point} thisArg

@@ -60,3 +60,3 @@ * @chainable

*/
subtractEquals(that: IPoint): Point;
subtractEquals(that: XY): Point;
/**

@@ -78,6 +78,6 @@ * Subtracts value from this point and returns a new one

* Multiplies this point by another value and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
multiply(that: IPoint): Point;
multiply(that: XY): Point;
/**

@@ -99,6 +99,6 @@ * Multiplies this point by a value and returns a new one

* Divides this point by another and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
divide(that: IPoint): Point;
divide(that: XY): Point;
/**

@@ -120,62 +120,62 @@ * Divides this point by a value and returns a new one

* Returns true if this point is equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
eq(that: IPoint): boolean;
eq(that: XY): boolean;
/**
* Returns true if this point is less than another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
lt(that: IPoint): boolean;
lt(that: XY): boolean;
/**
* Returns true if this point is less than or equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
lte(that: IPoint): boolean;
lte(that: XY): boolean;
/**
* Returns true if this point is greater another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
gt(that: IPoint): boolean;
gt(that: XY): boolean;
/**
* Returns true if this point is greater than or equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
gte(that: IPoint): boolean;
gte(that: XY): boolean;
/**
* Returns new point which is the result of linear interpolation with this one and another one
* @param {IPoint} that
* @param {XY} that
* @param {Number} t , position of interpolation, between 0 and 1 default 0.5
* @return {Point}
*/
lerp(that: IPoint, t?: number): Point;
lerp(that: XY, t?: number): Point;
/**
* Returns distance from this point and another one
* @param {IPoint} that
* @param {XY} that
* @return {Number}
*/
distanceFrom(that: IPoint): number;
distanceFrom(that: XY): number;
/**
* Returns the point between this point and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
midPointFrom(that: IPoint): Point;
midPointFrom(that: XY): Point;
/**
* Returns a new point which is the min of this and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
min(that: IPoint): Point;
min(that: XY): Point;
/**
* Returns a new point which is the max of this and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
max(that: IPoint): Point;
max(that: XY): Point;
/**

@@ -207,11 +207,11 @@ * Returns string representation of this point

* Sets x/y of this point from another point
* @param {IPoint} that
* @param {XY} that
* @chainable
*/
setFromPoint(that: IPoint): this;
setFromPoint(that: XY): this;
/**
* Swaps x/y of this point and another point
* @param {IPoint} that
* @param {XY} that
*/
swap(that: IPoint): void;
swap(that: XY): void;
/**

@@ -226,7 +226,7 @@ * return a cloned instance of the point

* @memberOf fabric.util
* @param {IPoint} origin The origin of the rotation
* @param {XY} origin The origin of the rotation
* @param {TRadian} radians The radians of the angle for the rotation
* @return {Point} The new rotated point
*/
rotate(radians: TRadian, origin?: IPoint): Point;
rotate(radians: TRadian, origin?: XY): Point;
/**

@@ -233,0 +233,0 @@ * Apply transform t to point p

import type { FabricObject } from './shapes/Object/FabricObject';
import { TClassProperties } from './typedefs';
export declare const shadowDefaultValues: Partial<TClassProperties<Shadow>>;
type TShadowSerializedProps = {
color: string;
blur: number;
offsetX: number;
offsetY: number;
affectStroke: boolean;
nonScaling: boolean;
};
export declare class Shadow {

@@ -48,2 +57,3 @@ /**

id: number;
static ownDefaults: Partial<TClassProperties<Shadow>>;
/**

@@ -81,3 +91,3 @@ * @see {@link http://fabricjs.com/shadows|Shadow demo}

*/
toObject(): Record<string, unknown>;
toObject(): Partial<TShadowSerializedProps>;
/**

@@ -88,3 +98,3 @@ * Regex matching shadow offsetX, offsetY and blur (ex: "2px 2px 10px rgba(0,0,0,0.2)", "rgb(0,255,0) 2px 2px")

}
export declare const shadowDefaultValues: Partial<TClassProperties<Shadow>>;
export {};
//# sourceMappingURL=Shadow.d.ts.map

@@ -1,3 +0,2 @@

import { ControlRenderingStyleOverride } from '../controls/controls.render';
import { TClassProperties } from '../typedefs';
import type { ControlRenderingStyleOverride } from '../controls/controlRendering';
import { Group } from './Group';

@@ -7,2 +6,10 @@ import type { FabricObject } from './Object/FabricObject';

_objects: FabricObject[];
/**
* controls how selected objects are added during a multiselection event
* - `canvas-stacking` adds the selected object to the active selection while respecting canvas object stacking order
* - `selection-order` adds the selected object to the top of the stack,
* meaning that the stack is ordered by the order in which objects were selected
* @default `canvas-stacking`
*/
multiSelectionStacking: 'canvas-stacking' | 'selection-order';
constructor(objects?: FabricObject[], options?: any, objectsRelativeToGroup?: boolean);

@@ -15,2 +22,12 @@ /**

* @private
* @override we don't want the selection monitor to be active
*/
__objectSelectionMonitor(): void;
/**
* Adds objects with respect to {@link multiSelectionStacking}
* @param targets object to add to selection
*/
multiSelectAdd(...targets: FabricObject[]): void;
/**
* @private
* @param {FabricObject} object

@@ -67,3 +84,2 @@ * @param {boolean} [removeParentTransform] true if object is in canvas coordinate plane

}
export declare const activeSelectionDefaultValues: Partial<TClassProperties<ActiveSelection>>;
//# sourceMappingURL=ActiveSelection.d.ts.map

@@ -0,4 +1,6 @@

import type { ObjectEvents } from '../EventTypeDefs';
import { FabricObject } from './Object/FabricObject';
import { TClassProperties } from '../typedefs';
export declare class Circle extends FabricObject {
import { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
interface UniqueCircleProps {
/**

@@ -24,2 +26,15 @@ * Radius of this circle

endAngle: number;
}
export interface SerializedCircleProps extends SerializedObjectProps, UniqueCircleProps {
}
export interface CircleProps extends FabricObjectProps, UniqueCircleProps {
}
export declare const circleDefaultValues: UniqueCircleProps;
export declare class Circle<Props extends TProps<CircleProps> = Partial<CircleProps>, SProps extends SerializedCircleProps = SerializedCircleProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements UniqueCircleProps {
radius: number;
startAngle: number;
endAngle: number;
static cacheProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): Record<string, any>;
/**

@@ -55,3 +70,3 @@ * @private

*/
toObject(propertiesToInclude?: string[]): object;
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -80,4 +95,8 @@ * Returns svg representation of an instance

static fromElement(element: SVGElement, callback: (circle: Circle) => any): void;
/**
* @todo how do we declare this??
*/
static fromObject<T extends TProps<SerializedCircleProps>>(object: T): Promise<Circle<Partial<CircleProps>, SerializedCircleProps, ObjectEvents>>;
}
export declare const circleDefaultValues: Partial<TClassProperties<Circle>>;
export {};
//# sourceMappingURL=Circle.d.ts.map
import { TClassProperties } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
export declare class Ellipse extends FabricObject {
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export declare const ellipseDefaultValues: UniqueEllipseProps;
interface UniqueEllipseProps {
rx: number;
ry: number;
}
export interface SerializedEllipseProps extends SerializedObjectProps, UniqueEllipseProps {
}
export interface EllipseProps extends FabricObjectProps, UniqueEllipseProps {
}
export declare class Ellipse<Props extends TProps<EllipseProps> = Partial<EllipseProps>, SProps extends SerializedEllipseProps = SerializedEllipseProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements EllipseProps {
/**

@@ -16,9 +27,8 @@ * Horizontal radius

ry: number;
static cacheProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
/**
* Constructor
* @param {Object} [options] Options object
* @return {Ellipse} thisArg
*/
constructor(options: Record<string, unknown>);
/**
* @private

@@ -45,3 +55,3 @@ * @param {String} key

*/
toObject(propertiesToInclude?: string[]): Record<string, any>;
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -75,3 +85,3 @@ * Returns svg representation of an instance

}
export declare const ellipseDefaultValues: Partial<TClassProperties<Ellipse>>;
export {};
//# sourceMappingURL=Ellipse.d.ts.map
import type { CollectionEvents, ObjectEvents } from '../EventTypeDefs';
import { Point } from '../Point';
import type { TClassProperties } from '../typedefs';
import type { TClassProperties, TSVGReviver } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
import { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
export type LayoutContextType = 'initialization' | 'object_modified' | 'added' | 'removed' | 'layout_change' | 'imperative';

@@ -45,2 +46,18 @@ export type LayoutContext = {

};
export interface GroupOwnProps {
layout: LayoutStrategy;
subTargetCheck: boolean;
interactive: boolean;
}
export interface SerializedGroupProps extends SerializedObjectProps, GroupOwnProps {
objects: SerializedObjectProps[];
}
export interface GroupProps extends FabricObjectProps, GroupOwnProps {
}
export declare const groupDefaultValues: {
layout: string;
strokeWidth: number;
subTargetCheck: boolean;
interactive: boolean;
};
declare const Group_base: {

@@ -69,12 +86,19 @@ new (...args: any[]): {

findNewUpperIndex(object: import("../EventTypeDefs").BaseFabricObject, idx: number, intersecting?: boolean | undefined): number;
collectObjects({ left, top, width, height }: import("../typedefs").TBBox, { includeIntersecting }?: {
includeIntersecting?: boolean | undefined;
}): import("./Object/InteractiveObject").InteractiveFabricObject<Partial<FabricObjectProps>, SerializedObjectProps, ObjectEvents>[];
};
} & {
new (options?: Record<string, unknown> | undefined): FabricObject<GroupEvents>;
_fromObject(object: Record<string, unknown>, { extraParam, ...options }?: {
new (options?: GroupProps): FabricObject<GroupProps, SerializedGroupProps, GroupEvents>;
ownDefaults: Record<string, any>;
getDefaults(): Record<string, any>;
stateProperties: string[];
cacheProperties: string[];
_fromObject<S extends import("./Object/Object").FabricObject<Partial<import("./Object/types/ObjectProps").ObjectProps>, SerializedObjectProps, ObjectEvents>>(object: Record<string, unknown>, { extraParam, ...options }?: {
extraParam?: string | undefined;
signal?: AbortSignal | undefined;
}): Promise<import("./Object/Object").FabricObject<ObjectEvents>>;
fromObject(object: Record<string, unknown>, options?: {
}): Promise<S>;
fromObject<T extends TProps<SerializedObjectProps>>(object: T, options?: {
signal?: AbortSignal | undefined;
} | undefined): Promise<import("./Object/Object").FabricObject<ObjectEvents>>;
} | undefined): Promise<import("./Object/Object").FabricObject<Partial<import("./Object/types/ObjectProps").ObjectProps>, SerializedObjectProps, ObjectEvents>>;
};

@@ -91,3 +115,2 @@ /**

* `fit-content`, `fit-content-lazy`, `fixed`, `clip-path` are supported out of the box
* @type LayoutStrategy
* @default

@@ -118,2 +141,8 @@ */

protected _activeObjects: FabricObject[];
static stateProperties: string[];
static ownDefaults: Record<string, any>;
private __objectSelectionTracker;
private __objectSelectionDisposer;
private _firstLayoutDone;
static getDefaults(): Record<string, any>;
/**

@@ -126,3 +155,3 @@ * Constructor

*/
constructor(objects?: FabricObject[], options?: any, objectsRelativeToGroup?: boolean);
constructor(objects?: FabricObject[], options?: Partial<GroupProps>, objectsRelativeToGroup?: boolean);
/**

@@ -140,3 +169,3 @@ * Checks if object can enter group and logs relevant warnings

*/
protected _filterObjectsBeforeEnteringGroup(objects: FabricObject[]): FabricObject<ObjectEvents>[];
protected _filterObjectsBeforeEnteringGroup(objects: FabricObject[]): FabricObject<Partial<FabricObjectProps>, SerializedObjectProps, ObjectEvents>[];
/**

@@ -193,3 +222,3 @@ * Add objects

*/
__objectMonitor(opt: any): void;
__objectMonitor(ev: ObjectEvents['modified']): void;
/**

@@ -199,3 +228,3 @@ * keeps track of the selected objects

*/
__objectSelectionMonitor(selected: boolean, opt: any): void;
__objectSelectionMonitor<T extends boolean>(selected: T, { target: object }: ObjectEvents[T extends true ? 'selected' : 'deselected']): void;
/**

@@ -269,3 +298,5 @@ * @private

*/
triggerLayout(context: any): void;
triggerLayout<T extends this['layout']>(context?: Partial<LayoutResult> & {
layout?: T;
}): void;
/**

@@ -285,3 +316,3 @@ * @private

*/
_applyLayoutStrategy(context: any): void;
_applyLayoutStrategy(context: LayoutContext): void;
/**

@@ -296,3 +327,3 @@ * Override this method to customize layout.

*/
getLayoutStrategyResult(layoutDirective: LayoutStrategy, objects: FabricObject[], context: LayoutContext): any;
getLayoutStrategyResult<T extends this['layout']>(layoutDirective: T, objects: FabricObject[], context: LayoutContext): any;
/**

@@ -307,3 +338,3 @@ * Override this method to customize layout.

*/
prepareBoundingBox(layoutDirective: LayoutStrategy, objects: FabricObject[], context: LayoutContext): any;
prepareBoundingBox<T extends this['layout']>(layoutDirective: T, objects: FabricObject[], context: LayoutContext): any;
/**

@@ -317,3 +348,3 @@ * Calculates center taking into account originX, originY while not being sure that width/height are initialized

*/
prepareInitialBoundingBox(layoutDirective: LayoutStrategy, objects: FabricObject[], context: LayoutContext): {
prepareInitialBoundingBox<T extends this['layout']>(layoutDirective: T, objects: FabricObject[], context: LayoutContext): {
centerX: number;

@@ -349,3 +380,3 @@ centerY: number;

*/
__serializeObjects(method: 'toObject' | 'toDatalessObject', propertiesToInclude?: string[]): Record<string, any>[];
__serializeObjects(method: 'toObject' | 'toDatalessObject', propertiesToInclude?: string[]): any[];
/**

@@ -356,3 +387,3 @@ * Returns object representation of an instance

*/
toObject(propertiesToInclude?: (keyof this)[]): Record<string, any>;
toObject<T extends Omit<GroupProps & TClassProperties<this>, keyof SerializedGroupProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SerializedGroupProps;
toString(): string;

@@ -363,9 +394,9 @@ dispose(): void;

*/
_createSVGBgRect(reviver?: (markup: string) => any): string;
_createSVGBgRect(reviver?: TSVGReviver): string;
/**
* Returns svg representation of an instance
* @param {Function} [reviver] Method for further parsing of svg representation.
* @param {TSVGReviver} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
_toSVG(reviver?: (markup: string) => any): string[];
_toSVG(reviver?: TSVGReviver): string[];
/**

@@ -381,3 +412,3 @@ * Returns styles-string for svg-export, specific version for group

*/
toClipPathSVG(reviver?: (markup: string) => any): string;
toClipPathSVG(reviver?: TSVGReviver): string;
/**

@@ -391,9 +422,5 @@ * @todo support loading from svg

*/
static fromObject({ objects, ...options }: {
[x: string]: any;
objects?: never[] | undefined;
}): Promise<Group>;
static fromObject<T extends TProps<SerializedGroupProps>>({ objects, ...options }: T): Promise<Group>;
}
export declare const groupDefaultValues: Partial<TClassProperties<Group>>;
export {};
//# sourceMappingURL=Group.d.ts.map

@@ -5,7 +5,30 @@ import type { BaseFilter } from '../filters/BaseFilter';

import { FabricObject } from './Object/FabricObject';
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export type ImageSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement;
interface UniqueImageProps {
srcFromAttribute: boolean;
minimumScaleTrigger: number;
cropX: number;
cropY: number;
imageSmoothing: boolean;
crossOrigin: string | null;
filters: BaseFilter[];
resizeFilter?: BaseFilter;
}
export declare const imageDefaultValues: Partial<UniqueImageProps> & Partial<FabricObjectProps>;
export interface SerializedImageProps extends SerializedObjectProps {
src: string;
crossOrigin: string | null;
filters: any[];
resizeFilter?: any;
cropX: number;
cropY: number;
}
export interface ImageProps extends FabricObjectProps, UniqueImageProps {
}
/**
* @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}
*/
export declare class Image extends FabricObject {
export declare class Image<Props extends TProps<ImageProps> = Partial<ImageProps>, SProps extends SerializedImageProps = SerializedImageProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements ImageProps {
/**

@@ -88,2 +111,7 @@ * When calling {@link Image.getSrc}, return value from element src with `element.getAttribute('src')`.

protected _filteredEl: ImageSource;
static cacheProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
/**

@@ -98,4 +126,4 @@ * Constructor

*/
constructor(elementId: string, options?: any);
constructor(element: ImageSource, options?: any);
constructor(elementId: string, options: Props);
constructor(element: ImageSource, options: Props);
/**

@@ -124,3 +152,3 @@ * Returns image element which this instance if based on

*/
getCrossOrigin(): any;
getCrossOrigin(): string | null;
/**

@@ -143,3 +171,3 @@ * Returns original size of an image

*/
toObject(propertiesToInclude?: (keyof this)[]): Record<string, any>;
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -161,3 +189,3 @@ * Returns true if an image has crop applied, inspecting values of cropX,cropY,width,height.

*/
getSrc(filtered?: boolean): any;
getSrc(filtered?: boolean): string;
/**

@@ -168,3 +196,3 @@ * Alias for getSrc

*/
getSvgSrc(filtered?: boolean): any;
getSvgSrc(filtered?: boolean): string;
/**

@@ -266,5 +294,5 @@ * Loads and sets source of an image\

*/
static fromObject({ filters: f, resizeFilter: rf, src, crossOrigin, ...object }: any, options: {
static fromObject<T extends TProps<SerializedImageProps>>({ filters: f, resizeFilter: rf, src, crossOrigin, ...object }: T, options: {
signal: AbortSignal;
}): Promise<Image>;
}): Promise<Image<TProps<ImageProps>, SerializedImageProps, ObjectEvents>>;
/**

@@ -277,3 +305,3 @@ * Creates an instance of Image from an URL string

*/
static fromURL(url: string, options?: LoadImageOptions): Promise<Image>;
static fromURL<T extends TProps<SerializedImageProps>>(url: string, options?: T & LoadImageOptions): Promise<Image>;
/**

@@ -291,3 +319,3 @@ * Returns {@link Image} instance from an SVG element

}
export declare const imageDefaultValues: Partial<TClassProperties<Image>>;
export {};
//# sourceMappingURL=Image.d.ts.map
import { ITextEvents } from './ITextBehavior';
import { ITextClickBehavior } from './ITextClickBehavior';
import { AssertKeys, TFiller } from '../../typedefs';
import type { SerializedTextProps, TextProps } from '../Text/Text';
type CursorBoundaries = {

@@ -10,2 +11,31 @@ left: number;

};
export declare const iTextDefaultValues: {
selectionStart: number;
selectionEnd: number;
selectionColor: string;
isEditing: boolean;
editable: boolean;
editingBorderColor: string;
cursorWidth: number;
cursorColor: string;
cursorDelay: number;
cursorDuration: number;
caching: boolean;
hiddenTextareaContainer: null;
_selectionDirection: null;
_reSpace: RegExp;
inCompositionMode: boolean;
keysMap: import("./constants").TKeyMapIText;
keysMapRtl: import("./constants").TKeyMapIText;
ctrlKeysMapDown: import("./constants").TKeyMapIText;
ctrlKeysMapUp: import("./constants").TKeyMapIText;
};
interface UniqueITextProps {
selectionStart: number;
selectionEnd: number;
}
export interface SerializedITextProps extends SerializedTextProps, UniqueITextProps {
}
export interface ITextProps extends TextProps, UniqueITextProps {
}
/**

@@ -54,3 +84,3 @@ * @fires changed

*/
export declare class IText<EventSpec extends ITextEvents = ITextEvents> extends ITextClickBehavior<EventSpec> {
export declare class IText<Props extends ITextProps = ITextProps, SProps extends SerializedITextProps = SerializedITextProps, EventSpec extends ITextEvents = ITextEvents> extends ITextClickBehavior<Props, SProps, EventSpec> implements UniqueITextProps {
/**

@@ -128,2 +158,7 @@ * Index where text selection starts (or where cursor is when there is no selection)

caching: boolean;
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
get type(): string;
/**

@@ -302,25 +337,3 @@

}
export declare const iTextDefaultValues: {
type: string;
selectionStart: number;
selectionEnd: number;
selectionColor: string;
isEditing: boolean;
editable: boolean;
editingBorderColor: string;
cursorWidth: number;
cursorColor: string;
cursorDelay: number;
cursorDuration: number;
caching: boolean;
hiddenTextareaContainer: null;
_selectionDirection: null;
_reSpace: RegExp;
inCompositionMode: boolean;
keysMap: import("./constants").TKeyMapIText;
keysMapRtl: import("./constants").TKeyMapIText;
ctrlKeysMapDown: import("./constants").TKeyMapIText;
ctrlKeysMapUp: import("./constants").TKeyMapIText;
};
export {};
//# sourceMappingURL=IText.d.ts.map

@@ -6,3 +6,5 @@ import { ObjectEvents, TPointerEvent, TPointerEventInfo } from '../../EventTypeDefs';

import type { ValueAnimation } from '../../util/animation/ValueAnimation';
import { TextStyleDeclaration } from '../Text/StyledText';
import type { TextStyleDeclaration } from '../Text/StyledText';
import type { SerializedTextProps, TextProps } from '../Text/Text';
import { TProps } from '../Object/types';
export type ITextEvents = ObjectEvents & {

@@ -20,3 +22,3 @@ 'selection:changed': never;

};
export declare abstract class ITextBehavior<EventSpec extends ITextEvents = ITextEvents> extends Text<EventSpec> {
export declare abstract class ITextBehavior<Props extends TProps<TextProps> = Partial<TextProps>, SProps extends SerializedTextProps = SerializedTextProps, EventSpec extends ITextEvents = ITextEvents> extends Text<Props, SProps, EventSpec> {
abstract isEditing: boolean;

@@ -267,3 +269,3 @@ abstract cursorDelay: number;

*/
removeChars(start: number, end: number): void;
removeChars(start: number, end?: number): void;
/**

@@ -270,0 +272,0 @@ * insert characters at start position, before start position.

import type { TPointerEvent, TPointerEventInfo } from '../../EventTypeDefs';
import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import type { DragMethods } from '../Object/InteractiveObject';

@@ -7,3 +7,5 @@ import { DraggableTextDelegate } from './DraggableTextDelegate';

import { ITextKeyBehavior } from './ITextKeyBehavior';
export declare abstract class ITextClickBehavior<EventSpec extends ITextEvents = ITextEvents> extends ITextKeyBehavior<EventSpec> implements DragMethods {
import { TProps } from '../Object/types';
import { TextProps, SerializedTextProps } from '../Text/Text';
export declare abstract class ITextClickBehavior<Props extends TProps<TextProps> = Partial<TextProps>, SProps extends SerializedTextProps = SerializedTextProps, EventSpec extends ITextEvents = ITextEvents> extends ITextKeyBehavior<Props, SProps, EventSpec> implements DragMethods {
private __lastSelected;

@@ -31,3 +33,3 @@ private __lastClickTime;

onMouseDown(options: TPointerEventInfo): void;
isTripleClick(newPointer: IPoint): boolean;
isTripleClick(newPointer: XY): boolean;
/**

@@ -81,4 +83,4 @@ * Default handler for double click, select a word

*/
_getNewSelectionStartFromOffset(mouseOffset: IPoint, prevWidth: number, width: number, index: number, jlen: number): number;
_getNewSelectionStartFromOffset(mouseOffset: XY, prevWidth: number, width: number, index: number, jlen: number): number;
}
//# sourceMappingURL=ITextClickBehavior.d.ts.map
import { TPointerEvent } from '../../EventTypeDefs';
import { ITextBehavior, ITextEvents } from './ITextBehavior';
import type { TKeyMapIText } from './constants';
export declare abstract class ITextKeyBehavior<EventSpec extends ITextEvents = ITextEvents> extends ITextBehavior<EventSpec> {
import { TProps } from '../Object/types';
import { TextProps, SerializedTextProps } from '../Text/Text';
export declare abstract class ITextKeyBehavior<Props extends TProps<TextProps> = Partial<TextProps>, SProps extends SerializedTextProps = SerializedTextProps, EventSpec extends ITextEvents = ITextEvents> extends ITextBehavior<Props, SProps, EventSpec> {
/**

@@ -6,0 +8,0 @@ * For functionalities on keyDown

import { TClassProperties } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
import { Point } from '../Point';
export declare class Line extends FabricObject {
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
interface UniqueLineProps {
x1: number;
x2: number;
y1: number;
y2: number;
}
export interface SerializedLineProps extends SerializedObjectProps, UniqueLineProps {
}
export declare class Line<Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>, SProps extends SerializedLineProps = SerializedLineProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements UniqueLineProps {
/**
* x value or first line edge
* @type Number
* @type number
* @default

@@ -13,3 +23,3 @@ */

* y value or first line edge
* @type Number
* @type number
* @default

@@ -20,3 +30,3 @@ */

* x value or second line edge
* @type Number
* @type number
* @default

@@ -27,6 +37,7 @@ */

* y value or second line edge
* @type Number
* @type number
* @default
*/
y2: number;
static cacheProperties: string[];
/**

@@ -38,3 +49,3 @@ * Constructor

*/
constructor(points?: number[], options?: Partial<TClassProperties<Line>>);
constructor(points?: number[], options?: Props);
/**

@@ -44,3 +55,3 @@ * @private

*/
_setWidthHeight({ left, top }?: Partial<TClassProperties<Line>>): void;
_setWidthHeight({ left, top }?: Partial<Props>): void;
/**

@@ -70,5 +81,3 @@ * @private

*/
toObject(propertiesToInclude: string[]): {
[x: string]: any;
};
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
_getNonTransformedDimensions(): Point;

@@ -79,3 +88,3 @@ /**

*/
calcLinePoints(): Record<string, number>;
calcLinePoints(): UniqueLineProps;
private makeEdgeToOriginGetter;

@@ -121,5 +130,5 @@ /**

*/
static fromObject({ x1, y1, x2, y2, ...object }: Record<string, any>): Promise<import("./Object/Object").FabricObject<import("../EventTypeDefs").ObjectEvents>>;
static fromObject<T extends TProps<SerializedLineProps>>({ x1, y1, x2, y2, ...object }: T): Promise<Line<Partial<FabricObjectProps>, SerializedLineProps, ObjectEvents>>;
}
export declare const lineDefaultValues: Partial<TClassProperties<Line>>;
export {};
//# sourceMappingURL=Line.d.ts.map
export declare const stateProperties: string[];
export declare const cacheProperties: string[];
export declare const fabricObjectDefaultValues: {
type: string;
originX: string;
originY: string;
top: number;
left: number;
width: number;
height: number;
scaleX: number;
scaleY: number;
flipX: boolean;
flipY: boolean;
opacity: number;
angle: number;
skewX: number;
skewY: number;
cornerSize: number;
touchCornerSize: number;
transparentCorners: boolean;
hoverCursor: null;
moveCursor: null;
padding: number;
borderColor: string;
borderDashArray: null;
cornerColor: string;
cornerStrokeColor: string;
cornerStyle: string;
cornerDashArray: null;
centeredScaling: boolean;
centeredRotation: boolean;
fill: string;
fillRule: string;
globalCompositeOperation: string;
backgroundColor: string;
selectionBackgroundColor: string;
stroke: null;
strokeWidth: number;
strokeDashArray: null;
strokeDashOffset: number;
strokeLineCap: string;
strokeLineJoin: string;
strokeMiterLimit: number;
shadow: null;
borderOpacityWhenMoving: number;
borderScaleFactor: number;
minScaleLimit: number;
selectable: boolean;
evented: boolean;
visible: boolean;
hasControls: boolean;
hasBorders: boolean;
perPixelTargetFind: boolean;
includeDefaultValues: boolean;
lockMovementX: boolean;
lockMovementY: boolean;
lockRotation: boolean;
lockScalingX: boolean;
lockScalingY: boolean;
lockSkewingX: boolean;
lockSkewingY: boolean;
lockScalingFlip: boolean;
excludeFromExport: boolean;
objectCaching: boolean;
noScaleCache: boolean;
strokeUniform: boolean;
dirty: boolean;
paintFirst: string;
activeOn: string;
colorProperties: string[];
clipPath: undefined;
inverted: boolean;
absolutePositioned: boolean;
FX_DURATION: number;
readonly originX: "left";
readonly originY: "top";
readonly top: 0;
readonly left: 0;
readonly width: 0;
readonly height: 0;
readonly scaleX: 1;
readonly scaleY: 1;
readonly flipX: false;
readonly flipY: false;
readonly opacity: 1;
readonly angle: 0;
readonly skewX: 0;
readonly skewY: 0;
readonly cornerSize: 13;
readonly touchCornerSize: 24;
readonly transparentCorners: true;
readonly hoverCursor: null;
readonly moveCursor: null;
readonly padding: 0;
readonly borderColor: "rgb(178,204,255)";
readonly borderDashArray: null;
readonly cornerColor: "rgb(178,204,255)";
readonly cornerStrokeColor: "";
readonly cornerStyle: "rect";
readonly cornerDashArray: null;
readonly centeredScaling: false;
readonly centeredRotation: true;
readonly fill: "rgb(0,0,0)";
readonly fillRule: "nonzero";
readonly globalCompositeOperation: "source-over";
readonly backgroundColor: "";
readonly selectionBackgroundColor: "";
readonly stroke: null;
readonly strokeWidth: 1;
readonly strokeDashArray: null;
readonly strokeDashOffset: 0;
readonly strokeLineCap: "butt";
readonly strokeLineJoin: "miter";
readonly strokeMiterLimit: 4;
readonly shadow: null;
readonly borderOpacityWhenMoving: 0.4;
readonly borderScaleFactor: 1;
readonly minScaleLimit: 0;
readonly selectable: true;
readonly evented: true;
readonly visible: true;
readonly hasControls: true;
readonly hasBorders: true;
readonly perPixelTargetFind: false;
readonly includeDefaultValues: true;
readonly lockMovementX: false;
readonly lockMovementY: false;
readonly lockRotation: false;
readonly lockScalingX: false;
readonly lockScalingY: false;
readonly lockSkewingX: false;
readonly lockSkewingY: false;
readonly lockScalingFlip: false;
readonly excludeFromExport: false;
readonly objectCaching: true;
readonly noScaleCache: true;
readonly strokeUniform: false;
readonly dirty: true;
readonly paintFirst: "fill";
readonly activeOn: "down";
readonly colorProperties: readonly ["fill", "stroke", "backgroundColor"];
readonly clipPath: undefined;
readonly inverted: false;
readonly absolutePositioned: false;
readonly FX_DURATION: 500;
};
//# sourceMappingURL=defaultValues.d.ts.map
import { ObjectEvents } from '../../EventTypeDefs';
import { FabricObjectSVGExportMixin } from './FabricObjectSVGExportMixin';
import { InteractiveFabricObject } from './InteractiveObject';
export interface FabricObject<EventSpec extends ObjectEvents = ObjectEvents> extends FabricObjectSVGExportMixin {
import { FabricObjectProps } from './types/FabricObjectProps';
import { TFabricObjectProps, SerializedObjectProps } from './types';
export interface FabricObject<Props extends TFabricObjectProps = Partial<FabricObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObjectSVGExportMixin {
}
export declare class FabricObject<EventSpec extends ObjectEvents = ObjectEvents> extends InteractiveFabricObject<EventSpec> {
export declare class FabricObject<Props extends TFabricObjectProps = Partial<FabricObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends InteractiveFabricObject<Props, SProps, EventSpec> {
}
export { cacheProperties, stateProperties } from './defaultValues';
export { cacheProperties } from './defaultValues';
//# sourceMappingURL=FabricObject.d.ts.map

@@ -8,3 +8,5 @@ import { Point } from '../../Point';

import type { Canvas } from '../../canvas/Canvas';
import type { ControlRenderingStyleOverride } from '../../controls/controls.render';
import type { ControlRenderingStyleOverride } from '../../controls/controlRendering';
import { FabricObjectProps } from './types/FabricObjectProps';
import { TFabricObjectProps, SerializedObjectProps } from './types';
type TOCoord = Point & {

@@ -15,4 +17,4 @@ corner: TCornerPoint;

type TControlSet = Record<string, Control>;
type TBorderRenderingStyleOverride = Partial<Pick<FabricObject, 'borderColor' | 'borderDashArray'>>;
type TStyleOverride = ControlRenderingStyleOverride & TBorderRenderingStyleOverride & Partial<Pick<FabricObject, 'hasBorders' | 'hasControls'> & {
type TBorderRenderingStyleOverride = Partial<Pick<InteractiveFabricObject, 'borderColor' | 'borderDashArray'>>;
type TStyleOverride = ControlRenderingStyleOverride & TBorderRenderingStyleOverride & Partial<Pick<InteractiveFabricObject, 'hasBorders' | 'hasControls'> & {
forActiveSelection: boolean;

@@ -25,3 +27,35 @@ }>;

export type FabricObjectWithDragSupport = InteractiveFabricObject & DragMethods;
export declare class InteractiveFabricObject<EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<EventSpec> {
export declare class InteractiveFabricObject<Props extends TFabricObjectProps = Partial<FabricObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements FabricObjectProps {
noScaleCache: boolean;
centeredScaling: false;
snapAngle?: TDegree;
snapThreshold?: TDegree;
lockMovementX: boolean;
lockMovementY: boolean;
lockRotation: boolean;
lockScalingX: boolean;
lockScalingY: boolean;
lockSkewingX: boolean;
lockSkewingY: boolean;
lockScalingFlip: boolean;
cornerSize: number;
touchCornerSize: number;
transparentCorners: boolean;
cornerColor: string;
cornerStrokeColor: string;
cornerStyle: 'rect' | 'circle';
cornerDashArray: number[] | null;
hasControls: boolean;
borderColor: string;
borderDashArray: number[] | null;
borderOpacityWhenMoving: number;
borderScaleFactor: number;
hasBorders: boolean;
selectionBackgroundColor: string;
selectable: boolean;
evented: boolean;
perPixelTargetFind: boolean;
activeOn: 'down' | 'up';
hoverCursor: CSSStyleDeclaration['cursor'] | null;
moveCursor: CSSStyleDeclaration['cursor'] | null;
/**

@@ -38,12 +72,2 @@ * Describe object's corner position in canvas element coordinates.

/**
* When `true`, cache does not get updated during scaling. The picture will get blocky if scaled
* too much and will be redrawn with correct details at the end of scaling.
* this setting is performance and application dependant.
* default to true
* since 1.7.0
* @type Boolean
* @default true
*/
noScaleCache: boolean;
/**
* keeps the value of the last hovered corner during mouse move.

@@ -64,13 +88,2 @@ * 0 is no corner, or 'mt', 'ml', 'mtr' etc..

/**
* The angle that an object will lock to while rotating.
* @type [TDegree]
*/
snapAngle?: TDegree;
/**
* The angle difference from the current snapped angle in which snapping should occur.
* When undefined, the snapThreshold will default to the snapAngle.
* @type [TDegree]
*/
snapThreshold?: TDegree;
/**
* holds the controls for the object.

@@ -95,8 +108,5 @@ * controls are added by default_controls.js

canvas?: Canvas;
static ownDefaults: Record<string, any>;
static getDefaults(): Record<string, any>;
/**
* Constructor
* @param {Object} [options] Options object
*/
constructor(options?: Record<string, unknown>);
/**
* Update width and height of the canvas for cache

@@ -109,7 +119,11 @@ * returns true or false if canvas needed resize.

/**
* Determines which corner has been clicked
* Determines which corner is under the mouse cursor, represented by `pointer`.
* This function is return a corner only if the object is the active one.
* This is done to avoid selecting corner of non active object and activating transformations
* rather than drag action. The default behavior of fabricJS is that if you want to transform
* an object, first you select it to show the control set
* @private
* @param {Object} pointer The pointer indicating the mouse position
* @param {boolean} forTouch indicates if we are looking for interaction area with a touch action
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or 0 if nothing is found.
*/

@@ -116,0 +130,0 @@ _findTargetCorner(pointer: Point, forTouch?: boolean): 0 | string;

@@ -5,5 +5,8 @@ import { ObjectEvents } from '../../EventTypeDefs';

import { Shadow } from '../../Shadow';
import type { TClassProperties, TDegree, TFiller, TSize, TCacheCanvasDimensions } from '../../typedefs';
import type { TDegree, TFiller, TSize, TCacheCanvasDimensions } from '../../typedefs';
import type { Group } from '../Group';
import type { Image } from '../Image';
import { SerializedObjectProps } from './types/SerializedObjectProps';
import { ObjectProps } from './types/ObjectProps';
import { TProps } from './types';
export type TCachedFabricObject = FabricObject & Required<Pick<FabricObject, 'zoomX' | 'zoomY' | '_cacheCanvas' | '_cacheContext' | 'cacheTranslationX' | 'cacheTranslationY'>> & {

@@ -40,331 +43,26 @@ _cacheContext: CanvasRenderingContext2D;

*/
export declare class FabricObject<EventSpec extends ObjectEvents = ObjectEvents> extends AnimatableObject<EventSpec> {
type: string;
/**
* Opacity of an object
* @type Number
* @default 1
*/
export declare class FabricObject<Props extends TProps<ObjectProps> = Partial<ObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends AnimatableObject<EventSpec> implements ObjectProps {
minScaleLimit: number;
opacity: number;
/**
* Size of object's controlling corners (in pixels)
* @type Number
* @default 13
*/
cornerSize: number;
/**
* Size of object's controlling corners when touch interaction is detected
* @type Number
* @default 24
*/
touchCornerSize: number;
/**
* When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)
* @type Boolean
* @default true
*/
transparentCorners: boolean;
/**
* Default cursor value used when hovering over this object on canvas
* @type CSSStyleDeclaration['cursor'] | null
* @default null
*/
hoverCursor: CSSStyleDeclaration['cursor'] | null;
/**
* Default cursor value used when moving this object on canvas
* @type CSSStyleDeclaration['cursor'] | null
* @default null
*/
moveCursor: CSSStyleDeclaration['cursor'] | null;
/**
* Color of controlling borders of an object (when it's active)
* @type String
* @default rgb(178,204,255)
*/
borderColor: string;
/**
* Array specifying dash pattern of an object's borders (hasBorder must be true)
* @since 1.6.2
* @type Array | null
* default null;
*/
borderDashArray: number[] | null;
/**
* Color of controlling corners of an object (when it's active)
* @type String
* @default rgb(178,204,255)
*/
cornerColor: string;
/**
* Color of controlling corners of an object (when it's active and transparentCorners false)
* @since 1.6.2
* @type String
* @default null
*/
cornerStrokeColor: string;
/**
* Specify style of control, 'rect' or 'circle'
* This is deprecated. In the futuer there will be a standard control render
* And you can swap it with one of the alternative proposed with the control api
* @since 1.6.2
* @type 'rect' | 'circle'
* @default rect
* @deprecated
*/
cornerStyle: 'rect' | 'circle';
/**
* Array specifying dash pattern of an object's control (hasBorder must be true)
* @since 1.6.2
* @type Array | null
*/
cornerDashArray: number[] | null;
/**
* When true, this object will use center point as the origin of transformation
* when being scaled via the controls.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
centeredScaling: false;
/**
* When true, this object will use center point as the origin of transformation
* when being rotated via the controls.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
centeredRotation: true;
/**
* When defined, an object is rendered via stroke and this property specifies its color
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default null
*/
stroke: string | TFiller | null;
/**
* Color of object's fill
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default rgb(0,0,0)
*/
paintFirst: 'fill' | 'stroke';
fill: string | TFiller | null;
/**
* Fill rule used to fill an object
* accepted values are nonzero, evenodd
* <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `globalCompositeOperation` instead)
* @type String
* @default nonzero
*/
fillRule: CanvasFillRule;
/**
* Composite rule used for canvas globalCompositeOperation
* @type String
* @default
*/
globalCompositeOperation: GlobalCompositeOperation;
/**
* Background color of an object.
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default
*/
backgroundColor: string;
/**
* Selection Background color of an object. colored layer behind the object when it is active.
* does not mix good with globalCompositeOperation methods.
* @type String
* @deprecated
* @default
*/
selectionBackgroundColor: string;
/**
* Array specifying dash pattern of an object's stroke (stroke must be defined)
* @type Array
* @default null;
*/
stroke: string | TFiller | null;
strokeDashArray: number[] | null;
/**
* Line offset of an object's stroke
* @type Number
* @default 0
*/
strokeDashOffset: number;
/**
* Line endings style of an object's stroke (one of "butt", "round", "square")
* @type String
* @default butt
*/
strokeLineCap: CanvasLineCap;
/**
* Corner style of an object's stroke (one of "bevel", "round", "miter")
* @type String
* @default
*/
strokeLineJoin: CanvasLineJoin;
/**
* Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke
* @type Number
* @default 4
*/
strokeMiterLimit: number;
/**
* Shadow object representing shadow of this shape
* @type Shadow
* @default null
*/
globalCompositeOperation: GlobalCompositeOperation;
backgroundColor: string;
shadow: Shadow | null;
/**
* Opacity of object's controlling borders when object is active and moving
* @type Number
* @default 0.4
*/
borderOpacityWhenMoving: number;
/**
* Scale factor of object's controlling borders
* bigger number will make a thicker border
* border is 1, so this is basically a border thickness
* since there is no way to change the border itself.
* @type Number
* @default 1
*/
borderScaleFactor: number;
/**
* Minimum allowed scale value of an object
* @type Number
* @default 0
*/
minScaleLimit: number;
/**
* When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).
* But events still fire on it.
* @type Boolean
* @default
*/
selectable: boolean;
/**
* When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4
* @type Boolean
* @default
*/
evented: boolean;
/**
* When set to `false`, an object is not rendered on canvas
* @type Boolean
* @default
*/
visible: boolean;
/**
* When set to `false`, object's controls are not displayed and can not be used to manipulate object
* @type Boolean
* @default
*/
hasControls: boolean;
/**
* When set to `false`, object's controlling borders are not rendered
* @type Boolean
* @default
*/
hasBorders: boolean;
/**
* When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
* @type Boolean
* @default
*/
perPixelTargetFind: boolean;
/**
* When `false`, default object's values are not included in its serialization
* @type Boolean
* @default
*/
includeDefaultValues: boolean;
/**
* When `true`, object horizontal movement is locked
* @type Boolean
* @default
*/
lockMovementX: boolean;
/**
* When `true`, object vertical movement is locked
* @type Boolean
* @default
*/
lockMovementY: boolean;
/**
* When `true`, object rotation is locked
* @type Boolean
* @default
*/
lockRotation: boolean;
/**
* When `true`, object horizontal scaling is locked
* @type Boolean
* @default
*/
lockScalingX: boolean;
/**
* When `true`, object vertical scaling is locked
* @type Boolean
* @default
*/
lockScalingY: boolean;
/**
* When `true`, object horizontal skewing is locked
* @type Boolean
* @default
*/
lockSkewingX: boolean;
/**
* When `true`, object vertical skewing is locked
* @type Boolean
* @default
*/
lockSkewingY: boolean;
/**
* When `true`, object cannot be flipped by scaling into negative values
* @type Boolean
* @default
*/
lockScalingFlip: boolean;
/**
* When `true`, object is not exported in OBJECT/JSON
* @since 1.6.3
* @type Boolean
* @default
*/
excludeFromExport: boolean;
/**
* When `true`, object is cached on an additional canvas.
* When `false`, object is not cached unless necessary ( clipPath )
* default to true
* @since 1.7.0
* @type Boolean
* @default true
*/
objectCaching: boolean;
clipPath?: FabricObject;
inverted: boolean;
absolutePositioned: boolean;
centeredRotation: boolean;
/**
* When set to `true`, object's cache will be rerendered next render call.
* since 1.7.0
* @type Boolean
* @default true
*/
dirty: boolean;
/**
* Determines if the fill or the stroke is drawn first (one of "fill" or "stroke")
* @type String
* @default
*/
paintFirst: 'fill' | 'stroke';
/**
* When 'down', object is set to active on mousedown/touchstart
* When 'up', object is set to active on mouseup/touchend
* Experimental. Let's see if this breaks anything before supporting officially
* @private
* since 4.4.0
* @type String
* @default 'down'
*/
activeOn: 'down' | 'up';
/**
* This list of properties is used to check if the state of an object is changed.

@@ -375,3 +73,3 @@ * This state change now is only used for children of groups to understand if a group

*/
stateProperties: string[];
static stateProperties: string[];
/**

@@ -384,31 +82,11 @@ * List of properties to consider when checking if cache needs refresh

*/
cacheProperties: string[];
static cacheProperties: string[];
/**
* a fabricObject that, without stroke define a clipping area with their shape. filled in black
* the clipPath object gets used when the object has rendered, and the context is placed in the center
* of the object cacheCanvas.
* If you want 0,0 of a clipPath to align with an object center, use clipPath.originX/Y to 'center'
* @type FabricObject
* When set to `true`, object's cache will be rerendered next render call.
* since 1.7.0
* @type Boolean
* @default true
*/
clipPath?: FabricObject;
dirty: boolean;
/**
* Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will make the object clip to the outside of the clipPath
* since 2.4.0
* @type boolean
* @default false
*/
inverted: boolean;
/**
* Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will have its top and left relative to canvas, and will
* not be influenced by the object transform. This will make the clipPath relative
* to the canvas, but clipping just a particular object.
* WARNING this is beta, this feature may change or be renamed.
* since 2.4.0
* @type boolean
* @default false
*/
absolutePositioned: boolean;
/**
* Quick access for the _cacheCanvas rendering context

@@ -488,7 +166,2 @@ * This is part of the objectCaching feature

/**
* A reference to the parent of the object
* Used to keep the original parent ref when the object has been added to an ActiveSelection, hence loosing the `group` ref
*/
__owningGroup?: Group;
/**
* Indicate if the object is sitting on a cache dedicated to it

@@ -509,7 +182,20 @@ * or is part of a larger cache for many object ( a group for example)

_transformDone?: boolean;
static ownDefaults: Record<string, any>;
static getDefaults(): Record<string, any>;
/**
* Legacy identifier of the class. Prefer using utils like isType or instanceOf
* Will be removed in fabric 7 or 8.
* The setter exists because is very hard to catch all the ways in which a type value
* could be set in the instance
* @TODO add sustainable warning message
* @type string
* @deprecated
*/
get type(): string;
set type(value: string);
/**
* Constructor
* @param {Object} [options] Options object
*/
constructor(options?: Partial<TClassProperties<FabricObject>>);
constructor(options?: Props);
/**

@@ -573,6 +259,6 @@ * Create a the canvas used to keep the cached copy of the object

* Returns an object representation of an instance
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @param {string[]} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @return {Object} Object representation of an instance
*/
toObject(propertiesToInclude?: string[]): Record<string, any>;
protected toObject(propertiesToInclude?: any[]): any;
/**

@@ -583,3 +269,3 @@ * Returns (dataless) object representation of an instance

*/
toDatalessObject(propertiesToInclude?: string[]): Record<string, any>;
toDatalessObject(propertiesToInclude?: any[]): any;
/**

@@ -589,3 +275,3 @@ * @private

*/
_removeDefaultValues(object: Record<string, any>): Record<string, any>;
_removeDefaultValues<T extends object>(object: T): Partial<T>;
/**

@@ -620,3 +306,4 @@ * Returns a string representation of an instance

/**
* @private
* Handles setting values on the instance and handling internal side effects
* @protected
* @param {String} key

@@ -802,3 +489,3 @@ * @param {*} value

*/
clone(propertiesToInclude: string[]): any;
clone(propertiesToInclude: string[]): this;
/**

@@ -835,2 +522,3 @@ * Creates an instance of Image out of an object

* @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2
* @param {Boolean} [options.viewportTransform] Account for canvas viewport transform
* @return {HTMLCanvasElement} Returns DOM element <canvas> with the FabricObject

@@ -856,3 +544,3 @@ */

/**
* Returns true if specified type is identical to the type of an instance
* Returns true if any of the specified types is identical to the type of an instance
* @param {String} type Type to check against

@@ -871,3 +559,3 @@ * @return {Boolean}

*/
toJSON(): Record<string, any>;
toJSON(): any;
/**

@@ -905,6 +593,6 @@ * Sets "angle" of an instance with centered rotation

*/
static _fromObject(object: Record<string, unknown>, { extraParam, ...options }?: {
static _fromObject<S extends FabricObject>(object: Record<string, unknown>, { extraParam, ...options }?: {
extraParam?: string;
signal?: AbortSignal;
}): Promise<FabricObject>;
}): Promise<S>;
/**

@@ -917,6 +605,6 @@ *

*/
static fromObject(object: Record<string, unknown>, options?: {
static fromObject<T extends TProps<SerializedObjectProps>>(object: T, options?: {
signal?: AbortSignal;
}): Promise<FabricObject>;
}): Promise<FabricObject<Partial<ObjectProps>, SerializedObjectProps, ObjectEvents>>;
}
//# sourceMappingURL=Object.d.ts.map

@@ -7,2 +7,3 @@ import type { TBBox, TCornerPoint, TDegree, TMat2D, TOriginX, TOriginY } from '../../typedefs';

import { ObjectEvents } from '../../EventTypeDefs';
import { ControlProps } from './types/ControlProps';
type TLineDescriptor = {

@@ -23,20 +24,3 @@ o: Point;

type TACoords = TCornerPoint;
export declare class ObjectGeometry<EventSpec extends ObjectEvents = ObjectEvents> extends ObjectOrigin<EventSpec> {
/**
* When true, an object is rendered as flipped horizontally
* @type Boolean
* @default false
*/
flipX: boolean;
/**
* When true, an object is rendered as flipped vertically
* @type Boolean
* @default false
*/
flipY: boolean;
/**
* Padding between object and its controlling borders (in pixels)
* @type Number
* @default 0
*/
export declare class ObjectGeometry<EventSpec extends ObjectEvents = ObjectEvents> extends ObjectOrigin<EventSpec> implements Pick<ControlProps, 'padding'> {
padding: number;

@@ -43,0 +27,0 @@ /**

@@ -5,88 +5,19 @@ import { Point } from '../../Point';

import { CommonMethods } from '../../CommonMethods';
export declare class ObjectOrigin<EventSpec> extends CommonMethods<EventSpec> {
/**
* Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}
* @type Number
* @default 0
*/
import { BaseProps } from './types/BaseProps';
import { FillStrokeProps } from './types/FillStrokeProps';
export declare class ObjectOrigin<EventSpec> extends CommonMethods<EventSpec> implements BaseProps, Pick<FillStrokeProps, 'strokeWidth' | 'strokeUniform'> {
top: number;
/**
* Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}
* @type Number
* @default 0
*/
left: number;
/**
* Object width
* @type Number
* @default
*/
width: number;
/**
* Object height
* @type Number
* @default
*/
height: number;
/**
* Object scale factor (horizontal)
* @type Number
* @default 1
*/
flipX: boolean;
flipY: boolean;
scaleX: number;
/**
* Object scale factor (vertical)
* @type Number
* @default 1
*/
scaleY: number;
/**
* Angle of skew on x axes of an object (in degrees)
* @type Number
* @default 0
*/
skewX: number;
/**
* Angle of skew on y axes of an object (in degrees)
* @type Number
* @default 0
*/
skewY: number;
/**
* Horizontal origin of transformation of an object (one of "left", "right", "center")
* See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups
* @type String
* @default 'left'
*/
originX: TOriginX;
/**
* Vertical origin of transformation of an object (one of "top", "bottom", "center")
* See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups
* @type String
* @default 'top'
*/
originY: TOriginY;
/**
* Angle of rotation of an object (in degrees)
* @type Number
* @default 0
*/
angle: TDegree;
/**
* Width of a stroke used to render this object
* @type Number
* @default 1
*/
strokeWidth: number;
/**
* When `false`, the stoke width will scale with the object.
* When `true`, the stroke will always match the exact pixel size entered for stroke width.
* this Property does not work on Text classes or drawing call that uses strokeText,fillText methods
* default to false
* @since 2.6.0
* @type Boolean
* @default false
* @type Boolean
* @default false
*/
strokeUniform: boolean;

@@ -93,0 +24,0 @@ /**

@@ -27,4 +27,14 @@ import { ObjectEvents } from '../../EventTypeDefs';

/**
* A reference to the parent of the object
* Used to keep the original parent ref when the object has been added to an ActiveSelection, hence loosing the `group` ref
*/
__owningGroup?: Group;
/**
* Returns instance's parent **EXCLUDING** `ActiveSelection`
* @param {boolean} [strict] exclude canvas as well
*/
getParent<T extends boolean>(strict?: T): TAncestor | undefined;
/**
* Checks if object is descendant of target
* Should be used instead of @link {Collection.contains} for performance reasons
* Should be used instead of {@link Group.contains} or {@link StaticCanvas.contains} for performance reasons
* @param {TAncestor} target

@@ -37,3 +47,3 @@ * @returns {boolean}

* @param {boolean} [strict] returns only ancestors that are objects (without canvas)
* @returns {Ancestors} ancestors from bottom to top
* @returns {Ancestors} ancestors (excluding `ActiveSelection`) from bottom to top
*/

@@ -40,0 +50,0 @@ getAncestors<T extends boolean>(strict?: T): Ancestors<T>;

import { Point } from '../Point';
import { PathData, TClassProperties } from '../typedefs';
import { type TPathSegmentsInfo } from '../util/path';
import { FabricObject } from './Object/FabricObject';
export declare class Path extends FabricObject {
import { TPathSegmentInfo, TSimplePathData } from '../util/path/typedefs';
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
import { TClassProperties, TSVGReviver } from '../typedefs';
interface UniquePathProps {
sourcePath?: string;
path?: TSimplePathData;
}
export interface SerializedPathProps extends SerializedObjectProps, UniquePathProps {
}
export interface PathProps extends FabricObjectProps, UniquePathProps {
}
export declare class Path<Props extends TProps<PathProps> = Partial<PathProps>, SProps extends SerializedPathProps = SerializedPathProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> {
/**

@@ -11,21 +21,22 @@ * Array of path points

*/
path: PathData;
path: TSimplePathData;
pathOffset: Point;
fromSVG?: boolean;
sourcePath?: string;
segmentsInfo?: TPathSegmentsInfo[];
segmentsInfo?: TPathSegmentInfo[];
static cacheProperties: string[];
/**
* Constructor
* @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {TSimplePathData} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {Object} [options] Options object
* @return {Path} thisArg
*/
constructor(path: PathData | string, { path, left, top, ...options }?: any);
constructor(path: TSimplePathData | string, { path, left, top, ...options }?: Props);
/**
* @private
* @param {PathData | string} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {TSimplePathData | string} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {boolean} [adjustPosition] pass true to reposition the object according to the bounding box
* @returns {Point} top left position of the bounding box, useful for complementary positioning
*/
_setPath(path: PathData | string, adjustPosition?: boolean): Point;
_setPath(path: TSimplePathData | string, adjustPosition?: boolean): Point;
/**

@@ -43,3 +54,3 @@ * @private

* Returns string representation of an instance
* @return {String} string representation of an instance
* @return {string} string representation of an instance
*/

@@ -52,5 +63,3 @@ toString(): string;

*/
toObject(propertiesToInclude?: (keyof this)[]): {
path: (string | number)[][];
};
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -61,5 +70,3 @@ * Returns dataless object representation of an instance

*/
toDatalessObject(propertiesToInclude?: (keyof this)[]): {
path: (string | number)[][];
};
toDatalessObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -75,14 +82,14 @@ * Returns svg representation of an instance

* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
* @return {string} svg representation of an instance
*/
toClipPathSVG(reviver: any): string;
toClipPathSVG(reviver: TSVGReviver): string;
/**
* Returns svg representation of an instance
* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
* @return {string} svg representation of an instance
*/
toSVG(reviver: any): string;
toSVG(reviver: TSVGReviver): string;
/**
* Returns number representation of an instance complexity
* @return {Number} complexity of this instance
* @return {number} complexity of this instance
*/

@@ -115,3 +122,3 @@ complexity(): number;

*/
static fromObject(object: any): Promise<import("./Object/Object").FabricObject<import("../EventTypeDefs").ObjectEvents>>;
static fromObject<T extends TProps<SerializedPathProps>>(object: T): Promise<Path<Partial<PathProps>, SerializedPathProps, ObjectEvents>>;
/**

@@ -126,5 +133,5 @@ * Creates an instance of Path from an SVG <path> element

*/
static fromElement(element: any, callback: any, options: any): void;
static fromElement(element: SVGElement, callback: (path: Path) => void, options: any): void;
}
export declare const pathDefaultValues: Partial<TClassProperties<Path>>;
export {};
//# sourceMappingURL=Path.d.ts.map

@@ -1,7 +0,9 @@

import { TClassProperties } from '../typedefs';
import { Polyline } from './Polyline';
export declare class Polygon extends Polyline {
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
protected isOpen(): boolean;
}
export declare const polygonDefaultValues: Partial<TClassProperties<Polygon>>;
//# sourceMappingURL=Polygon.d.ts.map

@@ -1,5 +0,11 @@

import { IPoint, Point } from '../Point';
import { XY, Point } from '../Point';
import { TClassProperties } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
export declare class Polyline extends FabricObject {
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export declare const polylineDefaultValues: Partial<TClassProperties<Polyline>>;
export interface SerializedPolylineProps extends SerializedObjectProps {
points: XY[];
}
export declare class Polyline<Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>, SProps extends SerializedPolylineProps = SerializedPolylineProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> {
/**

@@ -10,3 +16,3 @@ * Points array

*/
points: IPoint[];
points: XY[];
/**

@@ -23,2 +29,6 @@ * WARNING: Feature in progress

private initialized;
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
/**

@@ -28,6 +38,7 @@ * A list of properties that if changed trigger a recalculation of dimensions

*/
strokeBBoxAffectingProperties: (keyof this)[];
static layoutProperties: (keyof Polyline)[];
fromSVG: boolean;
pathOffset: Point;
strokeOffset: Point;
static cacheProperties: string[];
/**

@@ -52,3 +63,3 @@ * Constructor

*/
constructor(points?: IPoint[], { left, top, ...options }?: any);
constructor(points?: XY[], options?: Props);
protected isOpen(): boolean;

@@ -91,3 +102,3 @@ private _projectStrokeOnPoints;

*/
toObject(propertiesToInclude?: string[]): object;
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -132,5 +143,4 @@ * Returns svg representation of an instance

*/
static fromObject(object: Record<string, unknown>): Promise<import("./Object/Object").FabricObject<import("../EventTypeDefs").ObjectEvents>>;
static fromObject<T extends TProps<SerializedPolylineProps>>(object: T): Promise<Polyline<Partial<FabricObjectProps>, SerializedPolylineProps, ObjectEvents>>;
}
export declare const polylineDefaultValues: Partial<TClassProperties<Polyline>>;
//# sourceMappingURL=Polyline.d.ts.map
import { TClassProperties } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
export declare class Rect extends FabricObject {
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export declare const rectDefaultValues: Partial<TClassProperties<Rect>>;
interface UniqueRectProps {
rx: number;
ry: number;
}
export interface SerializedRectProps extends SerializedObjectProps, UniqueRectProps {
}
export interface RectProps extends FabricObjectProps, UniqueRectProps {
}
export declare class Rect<Props extends TProps<RectProps> = Partial<RectProps>, SProps extends SerializedRectProps = SerializedRectProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements RectProps {
/**

@@ -16,2 +27,5 @@ * Horizontal border radius

ry: number;
static cacheProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): Record<string, any>;
/**

@@ -22,3 +36,3 @@ * Constructor

*/
constructor(options: Record<string, unknown>);
constructor(options: Props);
/**

@@ -39,3 +53,3 @@ * Initializes rx/ry attributes

*/
toObject(propertiesToInclude?: string[]): Record<string, any>;
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
/**

@@ -64,3 +78,3 @@ * Returns svg representation of an instance

}
export declare const rectDefaultValues: Partial<TClassProperties<Rect>>;
export {};
//# sourceMappingURL=Rect.d.ts.map

@@ -1,2 +0,3 @@

import { ObjectEvents } from '../../EventTypeDefs';
import type { ObjectEvents } from '../../EventTypeDefs';
import type { FabricObjectProps, SerializedObjectProps, TProps } from '../Object/types';
import { FabricObject } from '../Object/FabricObject';

@@ -9,7 +10,7 @@ export type TextStyleDeclaration = Record<string, any>;

};
export declare abstract class StyledText<EventSpec extends ObjectEvents> extends FabricObject<EventSpec> {
export declare abstract class StyledText<Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> {
abstract styles: TextStyle;
protected abstract _textLines: string[][];
protected abstract _forceClearCache: boolean;
protected abstract _styleProperties: string[];
protected _forceClearCache: boolean;
static _styleProperties: readonly ["fontSize", "fontWeight", "fontFamily", "fontStyle", "underline", "overline", "linethrough", "stroke", "strokeWidth", "fill", "deltaY", "textBackgroundColor"];
abstract get2DCursorLocation(selectionStart: number, skipWrapping?: boolean): {

@@ -16,0 +17,0 @@ charIndex: number;

@@ -6,2 +6,5 @@ import { ObjectEvents } from '../../EventTypeDefs';

import { Path } from '../Path';
import type { FabricObjectProps, SerializedObjectProps, TProps } from '../Object/types';
type TPathSide = 'left' | 'right';
type TPathAlign = 'baseline' | 'center' | 'ascender' | 'descender';
/**

@@ -23,2 +26,22 @@ * Measure and return the info of a single grapheme.

} : Record<string, never>);
interface UniqueTextProps {
charSpacing: number;
lineHeight: number;
fontSize: number;
fontWeight: string;
fontFamily: string;
fontStyle: string;
pathSide: TPathSide;
pathAlign: TPathAlign;
underline: boolean;
overline: boolean;
linethrough: boolean;
textAlign: string;
direction: CanvasDirection;
path?: Path;
}
export interface SerializedTextProps extends SerializedObjectProps, UniqueTextProps {
}
export interface TextProps extends FabricObjectProps, UniqueTextProps {
}
/**

@@ -28,9 +51,9 @@ * Text class

*/
export declare class Text<EventSpec extends ObjectEvents = ObjectEvents> extends StyledText<EventSpec> {
export declare class Text<Props extends TProps<TextProps> = Partial<TextProps>, SProps extends SerializedTextProps = SerializedTextProps, EventSpec extends ObjectEvents = ObjectEvents> extends StyledText<Props, SProps, EventSpec> implements UniqueTextProps {
/**
* Properties which when set cause object to change dimensions
* @type Array
* @private
* Properties that requires a text layout recalculation when changed
* @type string[]
* @protected
*/
_dimensionAffectingProps: string[];
static textLayoutProperties: string[];
/**

@@ -150,3 +173,2 @@ * @private

textBackgroundColor: string;
protected _styleProperties: string[];
styles: TextStyle;

@@ -175,3 +197,3 @@ /**

*/
path: Path;
path: Path | null;
/**

@@ -187,6 +209,6 @@ * Offset amount for text path starting position

* Only used when text has a path
* @type {String} 'left|right'
* @type {TPathSide} 'left|right'
* @default
*/
pathSide: string;
pathSide: TPathSide;
/**

@@ -197,6 +219,6 @@ * How text is aligned to the path. This property determines

* This feature is in BETA, and its behavior may change
* @type String
* @type TPathAlign
* @default
*/
pathAlign: string;
pathAlign: TPathAlign;
/**

@@ -241,6 +263,6 @@ * @private

* @since 4.5.0
* @type {String} 'ltr|rtl'
* @type {CanvasDirection} 'ltr|rtl'
* @default
*/
direction: string;
direction: CanvasDirection;
/**

@@ -282,4 +304,8 @@ * contains characters bounding boxes

__lineWidths: number[];
_forceClearCache: boolean;
initialized?: true;
static cacheProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
constructor(text: string, options: any);

@@ -567,6 +593,2 @@ /**

/**
* @private
*/
_shouldClearDimensionCache(): any;
/**
* Measure a single line given its index. Used to calculate the initial

@@ -629,8 +651,3 @@ * text bounding box. The values are calculated and stored in __lineWidths cache.

*/
toObject(propertiesToInclude?: (keyof this)[]): {
path?: {
path: (string | number)[][];
} | undefined;
styles: import("../../util/misc/textStyles").TextStyleArray;
};
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
set(key: string | any, value?: any): this;

@@ -664,5 +681,5 @@ /**

*/
static fromObject(object: Record<string, any>): Promise<Text>;
static fromObject<T extends TProps<SerializedTextProps>>(object: T): Promise<Text<Partial<TextProps>, SerializedTextProps, ObjectEvents>>;
}
export declare const textDefaultValues: Partial<TClassProperties<Text>>;
export {};
//# sourceMappingURL=Text.d.ts.map
import { TClassProperties } from '../typedefs';
import { IText } from './IText/IText';
export declare const textboxDefaultValues: Partial<TClassProperties<Textbox>>;
/**

@@ -31,2 +32,17 @@ * Textbox class, based on IText, allows the user to resize the text rectangle

splitByGrapheme: boolean;
static textLayoutProperties: string[];
static ownDefaults: Record<string, any>;
static getDefaults(): {
controls: {
mr: import("../..").Control;
ml: import("../..").Control;
mb: import("../..").Control;
mt: import("../..").Control;
tl: import("../..").Control;
tr: import("../..").Control;
bl: import("../..").Control;
br: import("../..").Control;
mtr: import("../..").Control;
};
};
/**

@@ -170,3 +186,2 @@ * Unlike superclass's version of this function, Textbox does not update

}
export declare const textboxDefaultValues: Partial<TClassProperties<Textbox>>;
//# sourceMappingURL=Textbox.d.ts.map

@@ -1,4 +0,13 @@

import { TClassProperties } from '../typedefs';
import { FabricObject } from './Object/FabricObject';
export declare class Triangle extends FabricObject {
import type { FabricObjectProps, SerializedObjectProps, TProps } from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export declare const triangleDefaultValues: {
width: number;
height: number;
};
export declare class Triangle<Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>, SProps extends SerializedObjectProps = SerializedObjectProps, EventSpec extends ObjectEvents = ObjectEvents> extends FabricObject<Props, SProps, EventSpec> implements FabricObjectProps {
static ownDefaults: Record<string, any>;
static getDefaults(): {
[x: string]: any;
};
/**

@@ -16,3 +25,2 @@ * @private

}
export declare const triangleDefaultValues: Partial<TClassProperties<Triangle>>;
//# sourceMappingURL=Triangle.d.ts.map
import { BaseFabricObject } from './EventTypeDefs';
import type { Gradient } from './gradient/Gradient';
import type { Pattern } from './Pattern';
import type { Point } from './Point';
import type { XY, Point } from './Point';
interface NominalTag<T> {

@@ -52,6 +52,2 @@ nominalTag?: T;

/**
* SVG path commands
*/
export type PathData = (string | number)[][];
/**
* An invalid keyword and an empty string will be handled as the `anonymous` keyword.

@@ -79,2 +75,3 @@ * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes

};
export type TRectBounds = [min: XY, max: XY];
export type TToCanvasElementOptions = {

@@ -81,0 +78,0 @@ left?: number;

@@ -1,8 +0,3 @@

/**
* requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method
* @param {Function} callback Callback to invoke
*/
export declare function requestAnimFrame(callback: FrameRequestCallback): number;
export declare function cancelAnimFrame(handle: number): void;
//# sourceMappingURL=AnimationFrameProvider.d.ts.map

@@ -8,3 +8,3 @@ /**

*/
export declare function wrapElement(element: any, wrapper: any): any;
export declare function wrapElement(element: HTMLElement, wrapper: HTMLDivElement): HTMLDivElement;
/**

@@ -15,3 +15,3 @@ * Returns element scroll offsets

*/
export declare function getScrollLeftTop(element: any): {
export declare function getScrollLeftTop(element: HTMLElement): {
left: number;

@@ -25,3 +25,3 @@ top: number;

*/
export declare function getElementOffset(element: any): {
export declare function getElementOffset(element: HTMLElement): {
left: number;

@@ -35,3 +35,3 @@ top: number;

*/
export declare function makeElementUnselectable(element: any): any;
export declare function makeElementUnselectable(element: HTMLElement): HTMLElement;
/**

@@ -42,4 +42,3 @@ * Makes element selectable

*/
export declare function makeElementSelectable(element: any): any;
export declare function cleanUpJsdomNode(element: any): void;
export declare function makeElementSelectable(element: HTMLElement): HTMLElement;
//# sourceMappingURL=dom_misc.d.ts.map

@@ -1,9 +0,9 @@

import { IPoint } from '../../Point';
import { XY } from '../../Point';
import { TBBox } from '../../typedefs';
/**
* Calculates bounding box (left, top, width, height) from given `points`
* @param {IPoint[]} points
* @param {XY[]} points
* @return {Object} Object with left, top, width, height properties
*/
export declare const makeBoundingBoxFromPoints: (points: IPoint[]) => TBBox;
export declare const makeBoundingBoxFromPoints: (points: XY[]) => TBBox;
//# sourceMappingURL=boundingBoxFromPoints.d.ts.map

@@ -8,3 +8,3 @@ import type { FabricObject } from '../../shapes/Object/FabricObject';

*/
export declare const groupSVGElements: (elements: FabricObject[]) => FabricObject<import("../../EventTypeDefs").ObjectEvents>;
export declare const groupSVGElements: (elements: FabricObject[]) => FabricObject<Partial<import("../../shapes/Object/types").FabricObjectProps>, import("../../shapes/Object/types").SerializedObjectProps, import("../../EventTypeDefs").ObjectEvents>;
//# sourceMappingURL=groupSVGElements.d.ts.map

@@ -5,5 +5,5 @@ /**

* @param {CanvasRenderingContext2D} ctx context
* @param {Number} x x coordinate in canvasElementCoordinate, not fabric space
* @param {Number} y y coordinate in canvasElementCoordinate, not fabric space
* @param {Number} tolerance Tolerance pixels around the point, not alpha tolerance
* @param {Number} x x coordinate in canvasElementCoordinate, not fabric space. integer
* @param {Number} y y coordinate in canvasElementCoordinate, not fabric space. integer
* @param {Number} tolerance Tolerance pixels around the point, not alpha tolerance, integer
* @return {boolean} true if transparent

@@ -10,0 +10,0 @@ */

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import { TDegree, TMat2D } from '../../typedefs';

@@ -23,3 +23,3 @@ type TRotateMatrixArgs = {

* Apply transform t to point p
* @param {Point | IPoint} p The point to transform
* @param {Point | XY} p The point to transform
* @param {Array} t The transform

@@ -29,3 +29,3 @@ * @param {Boolean} [ignoreOffset] Indicates that the offset should not be applied

*/
export declare const transformPoint: (p: IPoint, t: TMat2D, ignoreOffset?: boolean) => Point;
export declare const transformPoint: (p: XY, t: TMat2D, ignoreOffset?: boolean) => Point;
/**

@@ -32,0 +32,0 @@ * Invert transformation t

@@ -45,3 +45,3 @@ import type { FabricObject } from '../../shapes/Object/FabricObject';

*/
export declare const enlivenObjects: (objects: any[], { signal, reviver }?: EnlivenObjectOptions) => Promise<FabricObject<import("../../EventTypeDefs").ObjectEvents>[]>;
export declare const enlivenObjects: (objects: any[], { signal, reviver }?: EnlivenObjectOptions) => Promise<FabricObject<Partial<import("../../shapes/Object/types").FabricObjectProps>, import("../../shapes/Object/types").SerializedObjectProps, import("../../EventTypeDefs").ObjectEvents>[]>;
/**

@@ -54,5 +54,5 @@ * Creates corresponding fabric instances residing in an object, e.g. `clipPath`

*/
export declare const enlivenObjectEnlivables: <R = Record<string, TFiller | FabricObject<import("../../EventTypeDefs").ObjectEvents> | null>>(serializedObject: any, { signal }?: {
export declare const enlivenObjectEnlivables: <R = Record<string, FabricObject<Partial<import("../../shapes/Object/types").FabricObjectProps>, import("../../shapes/Object/types").SerializedObjectProps, import("../../EventTypeDefs").ObjectEvents> | TFiller | null>>(serializedObject: any, { signal }?: {
signal?: AbortSignal | undefined;
}) => Promise<R>;
//# sourceMappingURL=objectEnlive.d.ts.map

@@ -8,2 +8,3 @@ /**

export declare const pick: <T extends Record<string, any>>(source: T, keys?: (keyof T)[]) => Partial<T>;
export declare const pickBy: <T extends Record<string, any>>(source: T, predicate: <K extends keyof T>(value: T[K], key: K, collection: T) => boolean) => Partial<T>;
//# sourceMappingURL=pick.d.ts.map
import type { Point } from '../../Point';
import type { FabricObject } from '../../shapes/Object/FabricObject';
import type { FabricObject } from '../../shapes/Object/Object';
import type { TMat2D } from '../../typedefs';

@@ -4,0 +4,0 @@ import type { StaticCanvas } from '../../canvas/StaticCanvas';

@@ -1,2 +0,2 @@

import { IPoint } from '../../../Point';
import { XY } from '../../../Point';
import { TProjection, TProjectStrokeOnPointsOptions } from './types';

@@ -10,3 +10,3 @@ /**

*/
export declare const projectStrokeOnPoints: (points: IPoint[], options: TProjectStrokeOnPointsOptions, openPath?: boolean) => TProjection[];
export declare const projectStrokeOnPoints: (points: XY[], options: TProjectStrokeOnPointsOptions, openPath?: boolean) => TProjection[];
//# sourceMappingURL=index.d.ts.map

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { StrokeProjectionsBase } from './StrokeProjectionsBase';

@@ -25,3 +25,3 @@ import { TProjection, TProjectStrokeOnPointsOptions } from './types';

T: Point;
constructor(A: IPoint, T: IPoint, options: TProjectStrokeOnPointsOptions);
constructor(A: XY, T: XY, options: TProjectStrokeOnPointsOptions);
calcOrthogonalProjection(from: Point, to: Point, magnitude?: number): Point;

@@ -28,0 +28,0 @@ /**

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { getBisector } from '../vectors';

@@ -34,3 +34,3 @@ import { StrokeProjectionsBase } from './StrokeProjectionsBase';

bisector: ReturnType<typeof getBisector>;
constructor(A: IPoint, B: IPoint, C: IPoint, options: TProjectStrokeOnPointsOptions);
constructor(A: XY, B: XY, C: XY, options: TProjectStrokeOnPointsOptions);
get bisectorVector(): Point;

@@ -37,0 +37,0 @@ get bisectorAngle(): import("../../../typedefs").TRadian;

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { TProjectStrokeOnPointsOptions, TProjection } from './types';

@@ -16,3 +16,3 @@ /**

*/
protected createSideVector(from: IPoint, to: IPoint): Point;
protected createSideVector(from: XY, to: XY): Point;
protected abstract calcOrthogonalProjection(from: Point, to: Point, magnitude?: number): Point;

@@ -19,0 +19,0 @@ protected projectOrthogonally(from: Point, to: Point, magnitude?: number): Point;

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import { TRadian } from '../../typedefs';

@@ -17,3 +17,3 @@ /**

*/
export declare const createVector: (from: IPoint, to: IPoint) => Point;
export declare const createVector: (from: XY, to: XY) => Point;
/**

@@ -20,0 +20,0 @@ * return the magnitude of a vector

@@ -15,6 +15,6 @@ import type { ActiveSelection } from '../shapes/ActiveSelection';

export declare const isActiveSelection: (fabricObject?: FabricObject) => fabricObject is ActiveSelection;
export declare const isTextObject: (fabricObject?: FabricObject) => fabricObject is Text<import("../EventTypeDefs").ObjectEvents>;
export declare const isInteractiveTextObject: (fabricObject?: FabricObject) => fabricObject is IText<import("../shapes/IText/ITextBehavior").ITextEvents> | Textbox;
export declare const isTextObject: (fabricObject?: FabricObject) => fabricObject is Text<Partial<import("../shapes/Text/Text").TextProps>, import("../shapes/Text/Text").SerializedTextProps, import("../EventTypeDefs").ObjectEvents>;
export declare const isInteractiveTextObject: (fabricObject?: FabricObject) => fabricObject is IText<import("../shapes/IText/IText").ITextProps, import("../shapes/IText/IText").SerializedITextProps, import("../shapes/IText/ITextBehavior").ITextEvents> | Textbox;
export declare const isFabricObjectCached: (fabricObject: FabricObject) => fabricObject is TCachedFabricObject;
export declare const isFabricObjectWithDragSupport: (fabricObject?: FabricObject) => fabricObject is FabricObjectWithDragSupport;
//# sourceMappingURL=types.d.ts.map

@@ -1,427 +0,51 @@

// FILTERS
import { BaseFilter } from './src/filters/BaseFilter';
import { BlendColor } from './src/filters/BlendColor';
import { BlendImage } from './src/filters/BlendImage';
import { Blur } from './src/filters/Blur';
import { Brightness } from './src/filters/Brightness';
import { ColorMatrix } from './src/filters/ColorMatrix';
import { Composed } from './src/filters/Composed';
import { Contrast } from './src/filters/Contrast';
import { Convolute } from './src/filters/Convolute';
import {
Sepia,
Brownie,
Vintage,
Kodachrome,
Technicolor,
Polaroid,
BlackWhite,
} from './src/filters/ColorMatrixFilters';
import { Gamma } from './src/filters/Gamma';
import { Grayscale } from './src/filters/Grayscale';
import { HueRotation } from './src/filters/HueRotation';
import { Invert } from './src/filters/Invert';
import { Noise } from './src/filters/Noise';
import { Pixelate } from './src/filters/Pixelate';
import { RemoveColor } from './src/filters/RemoveColor';
import { Resize } from './src/filters/Resize';
import { Saturation } from './src/filters/Saturation';
import { Vibrance } from './src/filters/Vibrance';
export { getEnv, getDocument, getWindow } from './src/env';
export { cache } from './src/cache';
export { VERSION as version, iMatrix } from './src/constants';
export { config } from './src/config';
export { classRegistry } from './src/ClassRegistry';
export { runningAnimations } from './src/util/animation/AnimationRegistry';
const filters = {
BaseFilter,
BlendColor,
BlendImage,
Blur,
Brightness,
ColorMatrix,
Composed,
Contrast,
Convolute,
Sepia,
Brownie,
Vintage,
Kodachrome,
Technicolor,
Polaroid,
BlackWhite,
Gamma,
Grayscale,
HueRotation,
Invert,
Noise,
Pixelate,
RemoveColor,
Resize,
Saturation,
Vibrance,
};
export { Observable } from './src/Observable';
// UTILS
export { StaticCanvas } from './src/canvas/StaticCanvas';
export { Canvas } from './src/canvas/Canvas';
import { cos } from './src/util/misc/cos';
import { sin } from './src/util/misc/sin';
import {
rotateVector,
createVector,
calcAngleBetweenVectors,
getUnitVector,
getBisector,
} from './src/util/misc/vectors';
import {
degreesToRadians,
radiansToDegrees,
} from './src/util/misc/radiansDegreesConversion';
import { rotatePoint } from './src/util/misc/rotatePoint';
import { projectStrokeOnPoints } from './src/util/misc/projectStroke';
import {
transformPoint,
invertTransform,
composeMatrix,
qrDecompose,
calcDimensionsMatrix,
calcRotateMatrix,
multiplyTransformMatrices,
isIdentityMatrix,
} from './src/util/misc/matrix';
import {
stylesFromArray,
stylesToArray,
hasStyleChanged,
} from './src/util/misc/textStyles';
import {
createCanvasElement,
createImage,
copyCanvasElement,
toDataURL,
} from './src/util/misc/dom';
import { toFixed } from './src/util/misc/toFixed';
import {
matrixToSVG,
parsePreserveAspectRatioAttribute,
parseUnit,
getSvgAttributes,
} from './src/util/misc/svgParsing';
import { groupSVGElements } from './src/util/misc/groupSVGElements';
import { findScaleToFit, findScaleToCover } from './src/util/misc/findScaleTo';
import { capValue } from './src/util/misc/capValue';
import {
saveObjectTransform,
resetObjectTransform,
addTransformToObject,
applyTransformToObject,
removeTransformFromObject,
sizeAfterTransform,
} from './src/util/misc/objectTransforms';
import { makeBoundingBoxFromPoints } from './src/util/misc/boundingBoxFromPoints';
import {
calcPlaneChangeMatrix,
sendPointToPlane,
transformPointRelativeToCanvas,
sendObjectToPlane,
} from './src/util/misc/planeChange';
import { graphemeSplit, escapeXml, capitalize } from './src/util/lang_string';
import {
loadImage,
enlivenObjects,
enlivenObjectEnlivables,
} from './src/util/misc/objectEnlive';
import { pick } from './src/util/misc/pick';
import {
joinPath,
parsePath,
makePathSimpler,
getSmoothPathFromPoints,
getPathSegmentsInfo,
getBoundsOfCurve,
getPointOnPath,
transformPath,
getRegularPolygonPath,
} from './src/util/path';
import { setStyle } from './src/util/dom_style';
import { isTouchEvent, getPointer } from './src/util/dom_event';
import {
// getScrollLeftTop,
getElementOffset,
cleanUpJsdomNode,
makeElementUnselectable,
makeElementSelectable,
} from './src/util/dom_misc';
import { isTransparent } from './src/util/misc/isTransparent';
import { mergeClipPaths } from './src/util/misc/mergeClipPaths';
import { animate, animateColor } from './src/util/animation/animate';
import * as ease from './src/util/animation/easing';
import {
requestAnimFrame,
cancelAnimFrame,
} from './src/util/animation/AnimationFrameProvider';
import { classRegistry } from './src/util/class_registry';
import { removeFromArray } from './src/util/internals/removeFromArray';
import { getRandomInt } from './src/util/internals/getRandomInt';
import { wrapElement } from './src/util/dom_misc';
import { request } from './src/util/dom_request';
import { removeTransformMatrixForSvgParsing } from './src/util/transform_matrix_removal';
import { parseFontDeclaration } from './src/parser/parseFontDeclaration';
export { Point } from './src/Point';
export { Intersection } from './src/Intersection';
export { Color } from './src/color/Color';
const util = {
rotatePoint,
removeFromArray,
getRandomInt,
wrapElement,
parsePreserveAspectRatioAttribute,
pick,
setStyle,
getSvgAttributes,
cos,
sin,
rotateVector,
createVector,
calcAngleBetweenVectors,
getUnitVector,
getBisector,
degreesToRadians,
radiansToDegrees,
projectStrokeOnPoints,
transformPoint,
invertTransform,
composeMatrix,
qrDecompose,
calcDimensionsMatrix,
calcRotateMatrix,
multiplyTransformMatrices,
isIdentityMatrix,
stylesFromArray,
stylesToArray,
hasStyleChanged,
getElementOffset,
createCanvasElement,
createImage,
copyCanvasElement,
toDataURL,
toFixed,
matrixToSVG,
groupSVGElements,
parseUnit,
// is anyone using it?
findScaleToFit,
findScaleToCover,
capValue,
saveObjectTransform,
resetObjectTransform,
addTransformToObject,
applyTransformToObject,
removeTransformFromObject,
makeBoundingBoxFromPoints,
calcPlaneChangeMatrix,
sendPointToPlane,
transformPointRelativeToCanvas,
sendObjectToPlane,
string: {
graphemeSplit,
capitalize,
escapeXml,
},
loadImage,
enlivenObjects,
enlivenObjectEnlivables,
joinPath,
parsePath,
makePathSimpler,
getSmoothPathFromPoints,
getPathSegmentsInfo,
getBoundsOfCurve,
getPointOnPath,
transformPath,
getRegularPolygonPath,
isTouchEvent,
getPointer,
// getScrollLeftTop,
cleanUpJsdomNode,
makeElementUnselectable,
makeElementSelectable,
isTransparent,
sizeAfterTransform,
mergeClipPaths,
request,
ease, // those are a lot of functions
animateColor,
animate,
requestAnimFrame,
cancelAnimFrame,
classRegistry,
// for test compatibility. We don't want to export it.
removeTransformMatrixForSvgParsing,
};
export { Gradient } from './src/gradient/Gradient';
export { Pattern } from './src/Pattern';
export { Shadow } from './src/Shadow';
// CONTROLS UTILS
export { BaseBrush } from './src/brushes/BaseBrush';
export { PencilBrush } from './src/brushes/PencilBrush';
export { CircleBrush } from './src/brushes/CircleBrush';
export { SprayBrush } from './src/brushes/SprayBrush';
export { PatternBrush } from './src/brushes/PatternBrush';
import { changeWidth } from './src/controls/changeWidth';
import {
renderCircleControl,
renderSquareControl,
} from './src/controls/controls.render';
import { dragHandler } from './src/controls/drag';
import { createPolyControls } from './src/controls/polyControl';
import {
rotationStyleHandler,
rotationWithSnapping,
} from './src/controls/rotate';
import {
scaleCursorStyleHandler,
scalingEqually,
scalingX,
scalingY,
} from './src/controls/scale';
import {
scaleOrSkewActionName,
scaleSkewCursorStyleHandler,
scalingXOrSkewingY,
scalingYOrSkewingX,
} from './src/controls/scaleSkew';
import {
skewCursorStyleHandler,
skewHandlerX,
skewHandlerY,
} from './src/controls/skew';
import { getLocalPoint } from './src/controls/util';
import { wrapWithFireEvent } from './src/controls/wrapWithFireEvent';
import { wrapWithFixedAnchor } from './src/controls/wrapWithFixedAnchor';
export { FabricObject as Object } from './src/shapes/Object/FabricObject';
export { Line } from './src/shapes/Line';
export { Circle } from './src/shapes/Circle';
export { Triangle } from './src/shapes/Triangle';
export { Ellipse } from './src/shapes/Ellipse';
export { Rect } from './src/shapes/Rect';
export { Path } from './src/shapes/Path';
export { Polyline } from './src/shapes/Polyline';
export { Polygon } from './src/shapes/Polygon';
export { Text } from './src/shapes/Text/Text';
export { IText } from './src/shapes/IText/IText';
export { Textbox } from './src/shapes/Textbox';
export { Group } from './src/shapes/Group';
export { ActiveSelection } from './src/shapes/ActiveSelection';
export { Image } from './src/shapes/Image';
export { createCollectionMixin } from './src/Collection';
/**
* @todo remove as unused
*/
const controlsUtils = {
scaleCursorStyleHandler,
skewCursorStyleHandler,
scaleSkewCursorStyleHandler,
rotationWithSnapping,
scalingEqually,
scalingX,
scalingY,
scalingYOrSkewingX,
scalingXOrSkewingY,
changeWidth,
skewHandlerX,
skewHandlerY,
dragHandler,
createPolyControls,
scaleOrSkewActionName,
rotationStyleHandler,
wrapWithFixedAnchor,
wrapWithFireEvent,
getLocalPoint,
renderCircleControl,
renderSquareControl,
};
export * as util from './src/util';
// EXPORTS
export * from './src/parser';
import { cache } from './src/cache';
import { VERSION as version, iMatrix } from './src/constants';
import { StaticCanvas } from './src/canvas/StaticCanvas';
import { Canvas } from './src/canvas/Canvas';
import { config } from './src/config';
import { loadSVGFromURL } from './src/parser/loadSVGFromURL';
import { loadSVGFromString } from './src/parser/loadSVGFromString';
import { initFilterBackend } from './src/filters/FilterBackend';
import { Canvas2dFilterBackend } from './src/filters/Canvas2dFilterBackend';
import { WebGLFilterBackend } from './src/filters/WebGLFilterBackend';
import { runningAnimations } from './src/util/animation/AnimationRegistry';
import { Observable } from './src/Observable';
import { Point } from './src/Point';
import { Intersection } from './src/Intersection';
import { Color } from './src/color/Color';
import { Control } from './src/controls/Control';
import { Gradient } from './src/gradient/Gradient';
import { Pattern } from './src/Pattern';
import { Shadow } from './src/Shadow';
import { BaseBrush } from './src/brushes/BaseBrush';
import { PencilBrush } from './src/brushes/PencilBrush';
import { CircleBrush } from './src/brushes/CircleBrush';
import { SprayBrush } from './src/brushes/SprayBrush';
import { PatternBrush } from './src/brushes/PatternBrush';
import { FabricObject as Object } from './src/shapes/Object/FabricObject';
import { Line } from './src/shapes/Line';
import { Circle } from './src/shapes/Circle';
import { Triangle } from './src/shapes/Triangle';
import { Ellipse } from './src/shapes/Ellipse';
import { Rect } from './src/shapes/Rect';
import { Path } from './src/shapes/Path';
import { Polyline } from './src/shapes/Polyline';
import { Polygon } from './src/shapes/Polygon';
import { Text } from './src/shapes/Text/Text';
import { IText } from './src/shapes/IText/IText';
import { Textbox } from './src/shapes/Textbox';
import { Group } from './src/shapes/Group';
import { ActiveSelection } from './src/shapes/ActiveSelection';
import { Image } from './src/shapes/Image';
import { getEnv, getDocument, getWindow, setEnvForTests } from './src/env';
import { createCollectionMixin } from './src/Collection';
import { parseAttributes } from './src/parser/parseAttributes';
import { parseElements } from './src/parser/parseElements';
import { getFilterBackend } from './src/filters/FilterBackend';
import { parseStyleAttribute } from './src/parser/parseStyleAttribute';
import { parsePointsAttribute } from './src/parser/parsePointsAttribute';
import { parseTransformAttribute } from './src/parser/parseTransformAttribute';
import { getCSSRules } from './src/parser/getCSSRules';
export { Control } from './src/controls/Control';
export * as controlsUtils from './src/controls';
import './src/controls/default_controls';
export {
parseElements,
parseAttributes,
cache,
version,
iMatrix,
createCollectionMixin,
StaticCanvas,
Canvas,
config,
loadSVGFromURL,
loadSVGFromString,
initFilterBackend,
Canvas2dFilterBackend,
WebGLFilterBackend,
runningAnimations,
Point,
Intersection,
Color,
Control,
Observable,
Gradient,
Pattern,
Shadow,
BaseBrush,
PencilBrush,
CircleBrush,
SprayBrush,
PatternBrush,
Object,
Line,
Circle,
Triangle,
Ellipse,
Rect,
Path,
Polyline,
Polygon,
Text,
IText,
Textbox,
Group,
ActiveSelection,
Image,
controlsUtils,
util,
filters,
getFilterBackend,
getEnv,
getDocument,
getWindow,
setEnvForTests,
parseStyleAttribute,
parsePointsAttribute,
parseFontDeclaration,
parseTransformAttribute,
getCSSRules,
};
export * from './src/filters';

@@ -1,7 +0,7 @@

import './src/env/node';
// first we set the env variable by importing the node env file
import { getNodeCanvas } from './src/env/node';
import type { Canvas as NodeCanvas, JpegConfig, PngConfig } from 'canvas';
import type { JpegConfig, PngConfig } from 'canvas';
import {
Canvas as CanvasBase,
getEnv,
StaticCanvas as StaticCanvasBase,

@@ -11,12 +11,6 @@ } from './fabric';

// TODO: move back to default values when refactoring to method
FabricObject.prototype.objectCaching = false;
FabricObject.ownDefaults.objectCaching = false;
export * from './fabric';
function getNodeCanvas(canvasEl: HTMLCanvasElement) {
const impl = getEnv().jsdomImplForWrapper(canvasEl);
return (impl._canvas || impl._image) as NodeCanvas;
}
export class StaticCanvas extends StaticCanvasBase {

@@ -23,0 +17,0 @@ getNodeCanvas() {

@@ -5,3 +5,3 @@ {

"homepage": "http://fabricjs.com/",
"version": "6.0.0-beta1",
"version": "6.0.0-beta3",
"author": "Juriy Zaytsev <kangax@gmail.com>",

@@ -44,3 +44,5 @@ "contributors": [

"scripts": {
"docs": "typedoc --out docs fabric.ts",
"cli": "node ./scripts/index.mjs",
"sandboxscript": "node ./scripts/sandbox.mjs",
"changelog": "auto-changelog -o change-output.md --unreleased-only",

@@ -50,8 +52,9 @@ "build": "npm run cli -- build",

"dev": "npm run cli -- dev",
"start": "npm run cli -- start",
"start": "npm run sandboxscript -- start",
"export": "npm run cli -- website export",
"build-tests": "rollup -c ./rollup.test.config.js",
"test:unit-browser": "npm run test -- -s unit -p 8080 -l -c ",
"test:visual-browser": "npm run test -- -s visual -p 8080 -l -c ",
"test": "npm run cli -- test",
"sandbox": "npm run sandboxscript -- sandbox",
"test:unit-browser": "npm run test -- -s unit -p 8080 -l -c chrome firefox",
"test:visual-browser": "npm run test -- -s visual -p 8081 -l -c chrome firefox",
"test:coverage": "nyc --silent qunit test/node_test_setup.js test/lib test/unit",

@@ -85,6 +88,7 @@ "test:visual:coverage": "nyc --silent --no-clean qunit test/node_test_setup.js test/lib test/visual",

"@types/node": "^17.0.21",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"abort-controller": "^3.0.0",
"auto-changelog": "^2.3.0",
"axios": "^0.27.2",
"babel-plugin-import-json-value": "^0.1.2",

@@ -94,5 +98,4 @@ "busboy": "^1.6.0",

"commander": "^9.1.0",
"deep-object-diff": "^1.1.7",
"eslint": "^8.23.1",
"eslint-config-prettier": "^8.5.0",
"eslint": "^8.34.0",
"eslint-config-prettier": "^8.6.0",
"fireworm": "^0.7.2",

@@ -104,2 +107,3 @@ "fs-extra": "^10.0.1",

"kill-port": "^2.0.1",
"micromatch": "^4.0.5",
"moment": "^2.29.1",

@@ -112,5 +116,7 @@ "nyc": "^15.1.0",

"rollup": "^3.9.1",
"semver": "^7.3.8",
"source-map-support": "^0.5.21",
"testem": "^3.8.0",
"tslib": "^2.4.1",
"typedoc": "^0.23.24",
"typescript": "^4.9.4"

@@ -131,2 +137,5 @@ },

"dist/index.node.d.ts"
],
"src/*": [
"src/*"
]

@@ -138,4 +147,4 @@ }

"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"default": "./dist/index.cjs",
"require": "./dist/index.js",
"default": "./dist/index.js",
"node": null,

@@ -142,0 +151,0 @@ "types": "./dist/index.d.ts"

@@ -45,3 +45,3 @@ # Fabric.js

- `JPG`, `PNG`, `JSON` and `SVG` i/o
- Typed and modular
- [Typed and modular](#migrating-to-v6)
- [Unit tested](CONTRIBUTING.md#%F0%9F%A7%AA%20testing)

@@ -64,2 +64,13 @@

## Migrating to v6
v6 is a **MAJOR** effort including migrating to TS and es6, countless fixes, rewrites and features.\
Currently in beta, refer to [#8299](../../issues/8299) for guidance.
```bash
$ npm install fabric@beta --save
// or
$ yarn add fabric@beta
```
## Installation

@@ -73,10 +84,2 @@

```js
// es6 imports
import { fabric } from 'fabric';
// or cjs
const fabric = require('fabric').fabric;
```
#### Browser

@@ -98,2 +101,11 @@

```js
// v6
import { Canvas, Rect } from 'fabric'; // browser
import { StaticCanvas, Rect } from 'fabric/node'; // node
// v5
import { fabric } from 'fabric';
```
<details><summary><b>Plain HTML</b></summary>

@@ -124,6 +136,7 @@

import React, { useEffect, useRef } from 'react';
import { fabric } from 'fabric';
import * as fabric from 'fabric'; // v6
import { fabric } from 'fabric'; // v5
export const FabricJSCanvas = () => {
const canvasEl = useRef(null);
const canvasEl = useRef<HTMLCanvasElement>(null);
useEffect(() => {

@@ -140,4 +153,4 @@ const options = { ... };

return (<canvas width="300" height="300" ref={canvasEl}/>)
});
return <canvas width="300" height="300" ref={canvasEl}/>;
};

@@ -151,4 +164,5 @@ ```

```js
const http = require('http');
const { fabric } = require('fabric');
import http from 'http';
import * as fabric from 'fabric/node'; // v6
import { fabric } from 'fabric'; // v5

@@ -187,2 +201,4 @@ const port = 8080;

See our ready to use [templates](./.codesandbox/templates/).
---

@@ -189,0 +205,0 @@

@@ -100,3 +100,3 @@ import { Color } from '../color/Color';

const circles = [];
const circles: Circle[] = [];

@@ -103,0 +103,0 @@ for (let i = 0; i < this.points.length; i++) {

import { Pattern } from '../Pattern';
import { PathData } from '../typedefs';
import { createCanvasElement } from '../util/misc/dom';
import type { Canvas } from '../canvas/Canvas';
import { PencilBrush } from './PencilBrush';
import { TSimplePathData } from '../util/path/typedefs';

@@ -59,3 +59,3 @@ export class PatternBrush extends PencilBrush {

*/
createPath(pathData: PathData) {
createPath(pathData: TSimplePathData) {
const path = super.createPath(pathData),

@@ -62,0 +62,0 @@ topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2);

@@ -5,13 +5,13 @@ import { ModifierKey, TEvent } from '../EventTypeDefs';

import { Path } from '../shapes/Path';
import { PathData } from '../typedefs';
import { getSmoothPathFromPoints, joinPath } from '../util/path';
import type { Canvas } from '../canvas/Canvas';
import { BaseBrush } from './BaseBrush';
import { TSimplePathData } from '../util/path/typedefs';
/**
* @private
* @param {PathData} pathData SVG path commands
* @param {TSimplePathData} pathData SVG path commands
* @returns {boolean}
*/
function isEmptySVGPath(pathData: PathData): boolean {
function isEmptySVGPath(pathData: TSimplePathData): boolean {
return joinPath(pathData) === 'M 0 0 Q 0 0 0 0 L 0 0';

@@ -210,6 +210,6 @@ }

* Converts points to SVG path
* @param {Array} points Array of points
* @return {PathData} SVG path commands
* @param {Point[]} points Array of points
* @return {TSimplePathData} SVG path commands
*/
convertPointsToSVGPath(points: Point[]): PathData {
convertPointsToSVGPath(points: Point[]): TSimplePathData {
const correction = this.width / 1000;

@@ -221,6 +221,6 @@ return getSmoothPathFromPoints(points, correction);

* Creates a Path object to add on canvas
* @param {PathData} pathData Path data
* @param {TSimplePathData} pathData Path data
* @return {Path} Path to add on canvas
*/
createPath(pathData: PathData) {
createPath(pathData: TSimplePathData): Path {
const path = new Path(pathData, {

@@ -227,0 +227,0 @@ fill: null,

@@ -126,3 +126,3 @@ import { Point } from '../Point';

const rects = [];
const rects: Rect[] = [];

@@ -129,0 +129,0 @@ for (let i = 0; i < this.sprayChunks.length; i++) {

import { config } from './config';
import { TRectBounds } from './typedefs';

@@ -86,5 +87,5 @@ export class Cache {

*/
boundsOfCurveCache = {};
boundsOfCurveCache: Record<string, TRectBounds> = {};
}
export const cache = new Cache();

@@ -37,3 +37,3 @@ //@ts-nocheck

var target = this.findTarget(e);
const target = this.findTarget(e);
if ('undefined' !== typeof target) {

@@ -61,5 +61,5 @@ this.__gesturesParams = {

var self = this.__gesturesParams.self,
t = this._currentTransform,
e = this.__gesturesParams.e;
const self = this.__gesturesParams.self;
const t = this._currentTransform;
const e = this.__gesturesParams.e;

@@ -157,4 +157,4 @@ t.action = 'scale';

_scaleObjectBy: function (s, e) {
var t = this._currentTransform,
target = t.target;
const t = this._currentTransform;
const target = t.target;
t.gestureScale = s;

@@ -171,3 +171,3 @@ target._scaling = true;

_rotateObjectByAngle: function (curAngle, e) {
var t = this._currentTransform;
const t = this._currentTransform;

@@ -174,0 +174,0 @@ if (t.target.get('lockRotation')) {

import { LEFT_CLICK, MIDDLE_CLICK, RIGHT_CLICK } from '../constants';
import { getEnv } from '../env';
import { getDocument, getWindow } from '../env';
import {

@@ -13,11 +13,9 @@ CanvasEvents,

import { Point } from '../Point';
import { ActiveSelection } from '../shapes/ActiveSelection';
import { Group } from '../shapes/Group';
import type { IText } from '../shapes/IText/IText';
import type { FabricObject } from '../shapes/Object/FabricObject';
import { AssertKeys } from '../typedefs';
import { isTouchEvent, stopEvent } from '../util/dom_event';
import { createCanvasElement } from '../util/misc/dom';
import { sendPointToPlane } from '../util/misc/planeChange';
import {
isActiveSelection,
isFabricObjectWithDragSupport,

@@ -120,10 +118,2 @@ isInteractiveTextObject,

/**
* Holds a reference to a pointer during mousedown to compare on mouse up and determine
* if it was a click event
* @type FabricObject
* @private
*/
declare _previousPointer: Point;
private _isClick: boolean;

@@ -180,3 +170,3 @@

eventTypePrefix = this._getEventPrefix();
functor(getEnv().window, 'resize', this._onResize);
functor(getWindow(), 'resize', this._onResize);
functor(canvasElement, eventTypePrefix + 'down', this._onMouseDown);

@@ -224,3 +214,3 @@ functor(

removeListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}up`,

@@ -230,3 +220,3 @@ this._onMouseUp as EventListener

removeListener(
getEnv().document,
getDocument(),
'touchend',

@@ -237,3 +227,3 @@ this._onTouchEnd as EventListener,

removeListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}move`,

@@ -244,3 +234,3 @@ this._onMouseMove as EventListener,

removeListener(
getEnv().document,
getDocument(),
'touchmove',

@@ -635,3 +625,3 @@ this._onMouseMove as EventListener,

addListener(
getEnv().document,
getDocument(),
'touchend',

@@ -642,3 +632,3 @@ this._onTouchEnd as EventListener,

addListener(
getEnv().document,
getDocument(),
'touchmove',

@@ -672,3 +662,3 @@ this._onMouseMove as EventListener,

addListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}up`,

@@ -678,3 +668,3 @@ this._onMouseUp as EventListener

addListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}move`,

@@ -700,3 +690,3 @@ this._onMouseMove as EventListener,

removeListener(
getEnv().document,
getDocument(),
'touchend',

@@ -707,3 +697,3 @@ this._onTouchEnd as EventListener,

removeListener(
getEnv().document,
getDocument(),
'touchmove',

@@ -739,3 +729,3 @@ this._onMouseMove as EventListener,

removeListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}up`,

@@ -745,3 +735,3 @@ this._onMouseUp as EventListener

removeListener(
getEnv().document,
getDocument(),
`${eventTypePrefix}move`,

@@ -854,3 +844,3 @@ this._onMouseMove as EventListener,

const targetWasActive = target === this._activeObject;
this._maybeGroupObjects(e);
this.handleSelection(e);
if (!shouldRender) {

@@ -1113,20 +1103,18 @@ shouldRender =

const pointer = this.getPointer(e, true);
// save pointer for check in __onMouseUp event
this._previousPointer = pointer;
const shouldRender = this._shouldRender(target),
shouldGroup = this._shouldGroup(e, target);
if (this._shouldClearSelection(e, target)) {
let shouldRender = this._shouldRender(target);
let grouped = false;
if (this.handleMultiSelection(e, target)) {
// active object might have changed while grouping
target = this._activeObject;
grouped = true;
shouldRender = true;
} else if (this._shouldClearSelection(e, target)) {
this.discardActiveObject(e);
} else if (shouldGroup) {
// in order for shouldGroup to be true, target needs to be true
this._handleGrouping(e, target!);
target = this._activeObject;
}
// we start a group selector rectangle if
// selection is enabled
// and there is no target, or the following 3 condition both apply
// and there is no target, or the following 3 conditions are satisfied:
// target is not selectable ( otherwise we selected it )
// target is not editing
// target is not already selected ( otherwise we drage )
// target is not already selected ( otherwise we drag )
if (

@@ -1136,4 +1124,3 @@ this.selection &&

(!target.selectable &&
// @ts-ignore
!target.isEditing &&
!(target as IText).isEditing &&
target !== this._activeObject))

@@ -1143,6 +1130,6 @@ ) {

this._groupSelector = {
ex: p.x,
ey: p.y,
top: 0,
left: 0,
x: p.x,
y: p.y,
deltaY: 0,
deltaX: 0,
};

@@ -1160,3 +1147,3 @@ }

);
if (target === this._activeObject && (corner || !shouldGroup)) {
if (target === this._activeObject && (corner || !grouped)) {
this._setupCurrentTransform(e, target, alreadySelected);

@@ -1172,9 +1159,8 @@ const control = target.controls[corner],

}
const invalidate = shouldRender || shouldGroup;
// we clear `_objectsToRender` in case of a change in order to repopulate it at rendering
// run before firing the `down` event to give the dev a chance to populate it themselves
invalidate && (this._objectsToRender = undefined);
shouldRender && (this._objectsToRender = undefined);
this._handleEvent(e, 'down');
// we must renderAll so that we update the visuals
invalidate && this.requestRenderAll();
shouldRender && this.requestRenderAll();
}

@@ -1247,4 +1233,4 @@

groupSelector.left = pointer.x - groupSelector.ex;
groupSelector.top = pointer.y - groupSelector.ey;
groupSelector.deltaX = pointer.x - groupSelector.x;
groupSelector.deltaY = pointer.y - groupSelector.y;

@@ -1408,3 +1394,2 @@ this.renderTop();

// @TODO: investigate;
// @ts-ignore
transform.reset = false;

@@ -1455,8 +1440,9 @@ transform.shiftKey = e.shiftKey;

let hoverCursor = target.hoverCursor || this.hoverCursor;
const activeSelection = isActiveSelection(this._activeObject)
? this._activeObject
: null,
const activeSelection =
this._activeObject === this._activeSelection
? this._activeObject
: null,
// only show proper corner when group selection is not active
corner =
(!activeSelection || !activeSelection.contains(target)) &&
(!activeSelection || target.group !== activeSelection) &&
// here we call findTargetCorner always with undefined for the touch parameter.

@@ -1485,15 +1471,23 @@ // we assume that if you are using a cursor you do not need to interact with

// Grouping objects mixin
/**
* Return true if the current mouse event that generated a new selection should generate a group
* ## Handles multiple selection
* - toggles `target` selection (selects/deselects `target` if it isn't/is selected respectively)
* - sets the active object in case it is not set or in case there is a single active object left under active selection.
* ---
* - If the active object is the active selection we add/remove `target` from it
* - If not, add the active object and `target` to the active selection and make it the active object.
* @private
* @param {TPointerEvent} e Event object
* @param {FabricObject} target
* @return {Boolean}
* @param {FabricObject} target target of event to select/deselect
* @returns true if grouping occurred
*/
_shouldGroup(e: TPointerEvent, target?: FabricObject): boolean {
protected handleMultiSelection(
e: TPointerEvent,
target?: FabricObject
): this is AssertKeys<this, '_activeObject'> {
const activeObject = this._activeObject;
// check if an active object exists on canvas and if the user is pressing the `selectionKey` while canvas supports multi selection.
return (
const activeSelection = this._activeSelection;
const isAS = activeObject === activeSelection;
if (
// check if an active object exists on canvas and if the user is pressing the `selectionKey` while canvas supports multi selection.
!!activeObject &&

@@ -1505,173 +1499,113 @@ this._isSelectionKeyPressed(e) &&

target.selectable &&
// if all pre-requisite pass, the target is either something different from the current
// activeObject or if an activeSelection already exists
// TODO at time of writing why `activeObject.type === 'activeSelection'` matter is unclear.
// is a very old condition uncertain if still valid.
(activeObject !== target || activeObject.type === 'activeSelection') &&
// make sure `activeObject` and `target` aren't ancestors of each other
!target.isDescendantOf(activeObject) &&
!activeObject.isDescendantOf(target) &&
// group target and active object only if they are different objects
// else we try to find a subtarget of `ActiveSelection`
(activeObject !== target || isAS) &&
// make sure `activeObject` and `target` aren't ancestors of each other in case `activeObject` is not `ActiveSelection`
// if it is then we want to remove `target` from it
(isAS ||
(!target.isDescendantOf(activeObject) &&
!activeObject.isDescendantOf(target))) &&
// target accepts selection
!target.onSelect({ e: e })
);
}
/**
* Handles active selection creation for user event
* @private
* @param {TPointerEvent} e Event object
* @param {FabricObject} target
*/
_handleGrouping(e: TPointerEvent, target: FabricObject) {
let groupingTarget: FabricObject | undefined = target;
// Called always a shouldGroup, meaning that we can trust this._activeObject exists.
const activeObject = this._activeObject!;
// avoid multi select when shift click on a corner
if (activeObject.__corner) {
return;
}
if (groupingTarget === activeObject) {
// if it's a group, find target again, using activeGroup objects
groupingTarget = this.findTarget(e, true);
// if even object is not found or we are on activeObjectCorner, bail out
if (!groupingTarget || !groupingTarget.selectable) {
return;
!target.onSelect({ e }) &&
// make sure we are not on top of a control
!activeObject.__corner
) {
if (isAS) {
const prevActiveObjects =
activeSelection.getObjects() as FabricObject[];
if (target === activeSelection) {
// find target from active objects
target = this.searchPossibleTargets(
prevActiveObjects,
this.getPointer(e, true)
);
// if nothing is found bail out
if (!target || !target.selectable) {
return false;
}
}
if (target.group === activeSelection) {
// `target` is part of active selection => remove it
activeSelection.remove(target);
this._hoveredTarget = target;
this._hoveredTargets = [...this.targets];
if (activeSelection.size() === 1) {
// activate last remaining object
this._setActiveObject(activeSelection.item(0) as FabricObject, e);
}
} else {
// `target` isn't part of active selection => add it
activeSelection.multiSelectAdd(target);
this._hoveredTarget = activeSelection;
this._hoveredTargets = [...this.targets];
}
this._fireSelectionEvents(prevActiveObjects, e);
} else {
isInteractiveTextObject(activeObject) && activeObject.exitEditing();
// add the active object and the target to the active selection and set it as the active object
activeSelection.multiSelectAdd(activeObject, target);
this._hoveredTarget = activeSelection;
// ISSUE 4115: should we consider subTargets here?
// this._hoveredTargets = [];
// this._hoveredTargets = this.targets.concat();
this._setActiveObject(activeSelection, e);
this._fireSelectionEvents([activeObject], e);
}
return true;
}
if (activeObject && activeObject.type === 'activeSelection') {
this._updateActiveSelection(e, groupingTarget);
} else {
this._createActiveSelection(e, groupingTarget);
}
return false;
}
/**
* @private
* ## Handles selection
* - selects objects that are contained in (and possibly intersecting) the selection bounding box
* - sets the active object
* ---
* runs on mouse up
*/
_updateActiveSelection(e: TPointerEvent, target: FabricObject) {
const activeSelection = this._activeObject! as ActiveSelection,
currentActiveObjects = activeSelection.getObjects();
if (target.group === activeSelection) {
activeSelection.remove(target);
this._hoveredTarget = target;
this._hoveredTargets = this.targets.concat();
if (activeSelection.size() === 1) {
// activate last remaining object
this._setActiveObject(activeSelection.item(0) as FabricObject, e);
}
} else {
activeSelection.add(target);
this._hoveredTarget = activeSelection;
this._hoveredTargets = this.targets.concat();
protected handleSelection(
e: TPointerEvent
): this is AssertKeys<this, '_activeObject'> {
if (!this.selection || !this._groupSelector) {
return false;
}
this._fireSelectionEvents(currentActiveObjects as FabricObject[], e);
}
/**
* Generates and set as active the active selection from user events
* @private
*/
_createActiveSelection(e: TPointerEvent, target: FabricObject) {
const currentActive = this.getActiveObject()!;
const groupObjects = target.isInFrontOf(currentActive)
? [currentActive, target]
: [target, currentActive];
// @ts-ignore
currentActive.isEditing && currentActive.exitEditing();
// handle case: target is nested
const newActiveSelection = new ActiveSelection(groupObjects, {
canvas: this,
});
this._hoveredTarget = newActiveSelection;
// ISSUE 4115: should we consider subTargets here?
// this._hoveredTargets = [];
// this._hoveredTargets = this.targets.concat();
this._setActiveObject(newActiveSelection, e);
this._fireSelectionEvents([currentActive], e);
}
/**
* Finds objects inside the selection rectangle and group them
* @private
* @param {Event} e mouse event
*/
_groupSelectedObjects(e: TPointerEvent) {
const group = this._collectObjects(e);
// do not create group for 1 element only
if (group.length === 1) {
this.setActiveObject(group[0], e);
} else if (group.length > 1) {
const aGroup = new ActiveSelection(group.reverse(), {
canvas: this,
});
this.setActiveObject(aGroup, e);
}
}
/**
* @private
*/
_collectObjects(e: TPointerEvent) {
const group: FabricObject[] = [],
_groupSelector = this._groupSelector,
point1 = new Point(_groupSelector.ex, _groupSelector.ey),
point2 = point1.add(new Point(_groupSelector.left, _groupSelector.top)),
selectionX1Y1 = point1.min(point2),
selectionX2Y2 = point1.max(point2),
allowIntersect = !this.selectionFullyContained,
const { x, y, deltaX, deltaY } = this._groupSelector,
point1 = new Point(x, y),
point2 = point1.add(new Point(deltaX, deltaY)),
tl = point1.min(point2),
br = point1.max(point2),
size = br.subtract(tl),
isClick = point1.eq(point2);
// we iterate reverse order to collect top first in case of click.
for (let i = this._objects.length; i--; ) {
const currentObject = this._objects[i];
if (
!currentObject ||
!currentObject.selectable ||
!currentObject.visible
) {
continue;
}
const collectedObjects = this.collectObjects(
{
left: tl.x,
top: tl.y,
width: size.x,
height: size.y,
},
{ includeIntersecting: !this.selectionFullyContained }
) as FabricObject[];
if (
(allowIntersect &&
currentObject.intersectsWithRect(
selectionX1Y1,
selectionX2Y2,
true
)) ||
currentObject.isContainedWithinRect(
selectionX1Y1,
selectionX2Y2,
true
) ||
(allowIntersect &&
currentObject.containsPoint(selectionX1Y1, undefined, true)) ||
(allowIntersect &&
currentObject.containsPoint(selectionX2Y2, undefined, true))
) {
group.push(currentObject);
// only add one object if it's a click
if (isClick) {
break;
}
}
}
const objects = isClick
? collectedObjects[0]
? [collectedObjects[0]]
: []
: collectedObjects.length > 1
? collectedObjects.filter((object) => !object.onSelect({ e })).reverse()
: collectedObjects;
if (group.length > 1) {
return group.filter((object) => !object.onSelect({ e }));
// set active object
if (objects.length === 1) {
// set as active object
this.setActiveObject(objects[0], e);
} else if (objects.length > 1) {
// add to active selection and make it the active object
this._activeSelection.add(...objects);
this.setActiveObject(this._activeSelection, e);
}
return group;
}
/**
* @private
*/
_maybeGroupObjects(e: TPointerEvent) {
if (this.selection && this._groupSelector) {
this._groupSelectedObjects(e);
}
this.setCursor(this.defaultCursor);
// clear selection and current transformation
// cleanup
this._groupSelector = null;
return true;
}

@@ -1695,2 +1629,3 @@

destroy() {
this.removeListeners();
super.destroy();

@@ -1697,0 +1632,0 @@ this.textEditingManager.dispose();

@@ -1,2 +0,2 @@

import { getEnv } from '../env';
import { getDocument, getEnv } from '../env';
import { dragHandler } from '../controls/drag';

@@ -15,21 +15,14 @@ import { getActionFromCorner } from '../controls/util';

addTransformToObject,
resetObjectTransform,
saveObjectTransform,
} from '../util/misc/objectTransforms';
import { StaticCanvas, TCanvasSizeOptions } from './StaticCanvas';
import {
isActiveSelection,
isCollection,
isFabricObjectCached,
} from '../util/types';
import { isCollection } from '../util/types';
import { invertTransform, transformPoint } from '../util/misc/matrix';
import { isTransparent } from '../util/misc/isTransparent';
import { TMat2D, TOriginX, TOriginY, TSize } from '../typedefs';
import { AssertKeys, TMat2D, TOriginX, TOriginY, TSize } from '../typedefs';
import { degreesToRadians } from '../util/misc/radiansDegreesConversion';
import { getPointer, isTouchEvent } from '../util/dom_event';
import type { IText } from '../shapes/IText/IText';
import {
cleanUpJsdomNode,
makeElementUnselectable,
wrapElement,
} from '../util/dom_misc';
import { makeElementUnselectable, wrapElement } from '../util/dom_misc';
import { setStyle } from '../util/dom_style';

@@ -40,18 +33,33 @@ import type { BaseBrush } from '../brushes/BaseBrush';

import { sendPointToPlane } from '../util/misc/planeChange';
import { ActiveSelection } from '../shapes/ActiveSelection';
import type { TDestroyedCanvas } from './StaticCanvas';
type TDestroyedCanvas = Omit<
SelectableCanvas<CanvasEvents>,
| 'contextTop'
| 'contextCache'
| 'lowerCanvasEl'
| 'upperCanvasEl'
| 'cacheCanvasEl'
| 'wrapperEl'
> & {
wrapperEl?: HTMLDivElement;
cacheCanvasEl?: HTMLCanvasElement;
upperCanvasEl?: HTMLCanvasElement;
lowerCanvasEl?: HTMLCanvasElement;
contextCache?: CanvasRenderingContext2D | null;
contextTop?: CanvasRenderingContext2D | null;
export const DefaultCanvasProperties = {
uniformScaling: true,
uniScaleKey: 'shiftKey',
centeredScaling: false,
centeredRotation: false,
centeredKey: 'altKey',
altActionKey: 'shiftKey',
selection: true,
selectionKey: 'shiftKey',
selectionColor: 'rgba(100, 100, 255, 0.3)', // blue
selectionDashArray: [],
selectionBorderColor: 'rgba(255, 255, 255, 0.3)',
selectionLineWidth: 1,
selectionFullyContained: false,
hoverCursor: 'move',
moveCursor: 'move',
defaultCursor: 'default',
freeDrawingCursor: 'crosshair',
notAllowedCursor: 'not-allowed',
containerClass: 'canvas-container',
perPixelTargetFind: false,
targetFindTolerance: 0,
skipTargetFind: false,
preserveObjectStacking: false,
stopContextMenu: false,
fireRightClick: false,
fireMiddleClick: false,
enablePointerEvents: false,
};

@@ -441,3 +449,3 @@

/**
* hold a reference to a data structure used to track the selecion
* hold a reference to a data structure used to track the selection
* box on canvas drag

@@ -448,3 +456,8 @@ * on the current on going transform

*/
_groupSelector: any = null;
protected _groupSelector: {
x: number;
y: number;
deltaX: number;
deltaY: number;
} | null = null;

@@ -460,11 +473,2 @@ /**

/**
* a reference to the context of an additional canvas that is used for scratch operations
* @TODOL This is created automatically when needed, while it shouldn't. is probably not even often needed
* and is a memory waste. We should either have one that gets added/deleted
* @type CanvasRenderingContext2D
* @private
*/
declare contextCache: CanvasRenderingContext2D;
/**
* During a mouse event we may need the pointer multiple times in multiple functions.

@@ -495,10 +499,24 @@ * _absolutePointer holds a reference to the pointer in fabricCanvas/design coordinates that is valid for the event

static ownDefaults: Record<string, any> = DefaultCanvasProperties;
static getDefaults(): Record<string, any> {
return { ...super.getDefaults(), ...SelectableCanvas.ownDefaults };
}
declare upperCanvasEl: HTMLCanvasElement;
declare contextTop: CanvasRenderingContext2D;
declare wrapperEl: HTMLDivElement;
declare cacheCanvasEl: HTMLCanvasElement;
private declare pixelFindCanvasEl: HTMLCanvasElement;
private declare pixelFindContext: CanvasRenderingContext2D;
protected declare _isCurrentlyDrawing: boolean;
declare freeDrawingBrush?: BaseBrush;
declare _activeObject?: FabricObject;
protected readonly _activeSelection: ActiveSelection;
constructor(el: string | HTMLCanvasElement, options = {}) {
super(el, options);
this._activeSelection = new ActiveSelection([], { canvas: this });
}
protected initElements(el: string | HTMLCanvasElement) {

@@ -554,36 +572,8 @@ super.initElements(el);

_chooseObjectsToRender(): FabricObject[] {
const activeObjects = this.getActiveObjects();
let objsToRender, activeGroupObjects;
if (!this.preserveObjectStacking && activeObjects.length > 1) {
objsToRender = [];
activeGroupObjects = [];
for (let i = 0, length = this._objects.length; i < length; i++) {
const object = this._objects[i];
if (activeObjects.indexOf(object) === -1) {
objsToRender.push(object);
} else {
activeGroupObjects.push(object);
}
}
if (activeObjects.length > 1 && isCollection(this._activeObject)) {
this._activeObject._objects = activeGroupObjects;
}
objsToRender.push(...activeGroupObjects);
}
// in case a single object is selected render it's entire parent above the other objects
else if (!this.preserveObjectStacking && activeObjects.length === 1) {
const target = activeObjects[0],
ancestors = target.getAncestors(true);
const topAncestor = (
ancestors.length === 0 ? target : ancestors.pop()
) as FabricObject;
objsToRender = this._objects.slice();
const index = objsToRender.indexOf(topAncestor);
index > -1 && objsToRender.splice(objsToRender.indexOf(topAncestor), 1);
objsToRender.push(topAncestor);
} else {
objsToRender = this._objects;
}
return objsToRender;
const activeObject = this._activeObject;
return !this.preserveObjectStacking && activeObject
? this._objects
.filter((object) => !object.group && object !== activeObject)
.concat(activeObject)
: this._objects;
}

@@ -644,3 +634,3 @@

* Given a pointer on the canvas with a viewport applied,
* find out the opinter in
* find out the pointer in object coordinates
* @private

@@ -656,2 +646,16 @@ */

/**
* Set the canvas tolerance value for pixel taret find.
* Use only integer numbers.
* @private
*/
setTargetFindTolerance(value: number) {
value = Math.round(value);
this.targetFindTolerance = value;
const retina = this.getRetinaScaling();
const size = Math.ceil((value * 2 + 1) * retina);
this.pixelFindCanvasEl.width = this.pixelFindCanvasEl.height = size;
this.pixelFindContext.scale(retina, retina);
}
/**
* Returns true if object is transparent at a certain location

@@ -667,40 +671,22 @@ * Clarification: this is `is target transparent at location X or are controls there`

isTargetTransparent(target: FabricObject, x: number, y: number): boolean {
// in case the target is the activeObject, we cannot execute this optimization
// because we need to draw controls too.
if (isFabricObjectCached(target) && target !== this._activeObject) {
// optimizatio: we can reuse the cache
const normalizedPointer = this._normalizePointer(target, new Point(x, y)),
targetRelativeX = Math.max(
target.cacheTranslationX + normalizedPointer.x * target.zoomX,
0
),
targetRelativeY = Math.max(
target.cacheTranslationY + normalizedPointer.y * target.zoomY,
0
);
return isTransparent(
target._cacheContext,
Math.round(targetRelativeX),
Math.round(targetRelativeY),
this.targetFindTolerance
);
}
const ctx = this.contextCache,
originalColor = target.selectionBackgroundColor,
v = this.viewportTransform;
target.selectionBackgroundColor = '';
const tolerance = this.targetFindTolerance;
const ctx = this.pixelFindContext;
this.clearContext(ctx);
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
ctx.translate(-x + tolerance, -y + tolerance);
ctx.transform(...this.viewportTransform);
const selectionBgc = target.selectionBackgroundColor;
target.selectionBackgroundColor = '';
target.render(ctx);
target.selectionBackgroundColor = selectionBgc;
ctx.restore();
target.selectionBackgroundColor = originalColor;
return isTransparent(ctx, x, y, this.targetFindTolerance);
// our canvas is square, and made around tolerance.
// so tolerance in this case also represent the center of the canvas.
const enhancedTolerance = Math.round(tolerance * this.getRetinaScaling());
return isTransparent(
ctx,
enhancedTolerance,
enhancedTolerance,
enhancedTolerance
);
}

@@ -730,3 +716,6 @@

*/
_shouldClearSelection(e: TPointerEvent, target?: FabricObject): boolean {
_shouldClearSelection(
e: TPointerEvent,
target?: FabricObject
): target is undefined {
const activeObjects = this.getActiveObjects(),

@@ -905,5 +894,7 @@ activeObject = this._activeObject;

_drawSelection(ctx: CanvasRenderingContext2D): void {
const { ex, ey, left, top } = this._groupSelector,
start = new Point(ex, ey).transform(this.viewportTransform),
extent = new Point(ex + left, ey + top).transform(this.viewportTransform),
const { x, y, deltaX, deltaY } = this._groupSelector!,
start = new Point(x, y).transform(this.viewportTransform),
extent = new Point(x + deltaX, y + deltaY).transform(
this.viewportTransform
),
strokeOffset = this.selectionLineWidth / 2;

@@ -942,10 +933,8 @@ let minX = Math.min(start.x, extent.x),

* Method that determines what object we are clicking on
* the skipGroup parameter is for internal use, is needed for shift+click action
* 11/09/2018 TODO: would be cool if findTarget could discern between being a full target
* or the outside part of the corner.
* @param {Event} e mouse event
* @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through
* @return {FabricObject | null} the target found
*/
findTarget(e: TPointerEvent, skipGroup = false): FabricObject | undefined {
findTarget(e: TPointerEvent): FabricObject | undefined {
if (this.skipTargetFind) {

@@ -957,57 +946,43 @@ return undefined;

activeObject = this._activeObject,
aObjects = this.getActiveObjects(),
isTouch = isTouchEvent(e),
shouldLookForActive =
(aObjects.length > 1 && !skipGroup) || aObjects.length === 1;
aObjects = this.getActiveObjects();
// first check current group (if one exists)
// active group does not check sub targets like normal groups.
// if active group just exits.
this.targets = [];
// if we hit the corner of an activeObject, let's return that.
if (
// ts doesn't get that if shouldLookForActive is true, activeObject exists
activeObject &&
shouldLookForActive &&
activeObject._findTargetCorner(pointer, isTouch)
) {
return activeObject;
}
if (
aObjects.length > 1 &&
isActiveSelection(activeObject) &&
!skipGroup &&
this.searchPossibleTargets([activeObject], pointer)
) {
return activeObject;
}
let activeTarget;
let activeTargetSubs: FabricObject[] = [];
if (
// ts doesn't get that if aObjects has one object, activeObject exists
activeObject &&
aObjects.length === 1 &&
activeObject === this.searchPossibleTargets([activeObject], pointer)
) {
if (!this.preserveObjectStacking) {
if (activeObject && aObjects.length >= 1) {
if (activeObject._findTargetCorner(pointer, isTouchEvent(e))) {
// if we hit the corner of the active object, let's return that.
return activeObject;
} else {
activeTarget = activeObject;
activeTargetSubs = this.targets;
this.targets = [];
} else if (
aObjects.length > 1 &&
// check pointer is over active selection and possibly perform `subTargetCheck`
this.searchPossibleTargets([activeObject], pointer)
) {
// active selection does not select sub targets like normal groups
return activeObject;
} else if (
activeObject === this.searchPossibleTargets([activeObject], pointer)
) {
// active object is not an active selection
if (!this.preserveObjectStacking) {
return activeObject;
} else {
const subTargets = this.targets;
this.targets = [];
const target = this.searchPossibleTargets(this._objects, pointer);
if (
e[this.altSelectionKey as ModifierKey] &&
target &&
target !== activeObject
) {
// alt selection: select active object even though it is not the top most target
// restore targets
this.targets = subTargets;
return activeObject;
}
return target;
}
}
}
const target = this.searchPossibleTargets(this._objects, pointer);
if (
e[this.altSelectionKey as ModifierKey] &&
target &&
activeTarget &&
target !== activeTarget
) {
this.targets = activeTargetSubs;
return activeTarget;
}
return target;
return this.searchPossibleTargets(this._objects, pointer);
}

@@ -1211,3 +1186,2 @@

this.upperCanvasEl[prop] = value;
this.cacheCanvasEl[prop] = value;
}

@@ -1254,8 +1228,11 @@

protected _createCacheCanvas() {
this.cacheCanvasEl = this._createCanvasElement();
this.contextCache = this.cacheCanvasEl.getContext('2d')!;
this.pixelFindCanvasEl = this._createCanvasElement();
this.pixelFindContext = this.pixelFindCanvasEl.getContext('2d', {
willReadFrequently: true,
})!;
this.setTargetFindTolerance(this.targetFindTolerance);
}
protected _initWrapperElement() {
const container = getEnv().document.createElement('div');
const container = getDocument().createElement('div');
container.classList.add(this.containerClass);

@@ -1328,2 +1305,9 @@ this.wrapperEl = wrapElement(this.lowerCanvasEl, container);

/**
* Returns instance's active selection
*/
getActiveSelection() {
return this._activeSelection;
}
/**
* Returns an array with the current selected objects

@@ -1335,4 +1319,4 @@ * @return {FabricObject[]} active objects array

if (active) {
if (isActiveSelection(active)) {
return [...active._objects];
if (active === this._activeSelection) {
return [...(active as ActiveSelection)._objects];
} else {

@@ -1408,26 +1392,32 @@ return [active];

* @param {TPointerEvent} [e] Event (passed along when firing "object:selected")
* @chainable
* @return {Boolean} true if the object has been selected
*/
setActiveObject(object: FabricObject, e?: TPointerEvent) {
setActiveObject(
object: FabricObject,
e?: TPointerEvent
): this is AssertKeys<this, '_activeObject'> {
// we can't inline this, since _setActiveObject will change what getActiveObjects returns
const currentActives = this.getActiveObjects();
this._setActiveObject(object, e);
const selected = this._setActiveObject(object, e);
this._fireSelectionEvents(currentActives, e);
return selected;
}
/**
* This is a private method for now.
* This is supposed to be equivalent to setActiveObject but without firing
* any event. There is commitment to have this stay this way.
* This is the functional part of setActiveObject.
* @private
* @param {Object} object to set as active
* @param {Event} [e] Event (passed along when firing "object:selected")
* @return {Boolean} true if the selection happened
* @return {Boolean} true if the object has been selected
*/
_setActiveObject(object: FabricObject, e?: TPointerEvent) {
_setActiveObject(
object: FabricObject,
e?: TPointerEvent
): this is AssertKeys<this, '_activeObject'> {
if (this._activeObject === object) {
return false;
}
if (!this._discardActiveObject(e, object)) {
if (!this._discardActiveObject(e, object) && this._activeObject) {
// refused to deselect
return false;

@@ -1439,2 +1429,3 @@ }

this._activeObject = object;
return true;

@@ -1444,3 +1435,2 @@ }

/**
* This is a private method for now.
* This is supposed to be equivalent to discardActiveObject but without firing

@@ -1451,6 +1441,8 @@ * any selection events ( can still fire object transformation events ). There is commitment to have this stay this way.

* @param {Object} object the next object to set as active, reason why we are discarding this
* @return {Boolean} true if the selection happened
* @private
* @return {Boolean} true if the active object has been discarded
*/
_discardActiveObject(e?: TPointerEvent, object?: FabricObject) {
_discardActiveObject(
e?: TPointerEvent,
object?: FabricObject
): this is { _activeObject: undefined } {
const obj = this._activeObject;

@@ -1462,2 +1454,7 @@ if (obj) {

}
// clear active selection
if (obj === this._activeSelection) {
this._activeSelection.removeAll();
resetObjectTransform(this._activeSelection);
}
if (this._currentTransform && this._currentTransform.target === obj) {

@@ -1468,4 +1465,5 @@ // @ts-ignore

this._activeObject = undefined;
return true;
}
return true;
return false;
}

@@ -1479,5 +1477,5 @@

* @param {event} e
* @chainable
* @return {Boolean} true if the active object has been discarded
*/
discardActiveObject(e?: TPointerEvent) {
discardActiveObject(e?: TPointerEvent): this is { _activeObject: undefined } {
const currentActives = this.getActiveObjects(),

@@ -1491,4 +1489,5 @@ activeObject = this.getActiveObject();

}
this._discardActiveObject(e);
const discarded = this._discardActiveObject(e);
this._fireSelectionEvents(currentActives, e);
return discarded;
}

@@ -1520,23 +1519,25 @@

*/
destroy(this: TDestroyedCanvas) {
destroy() {
const wrapperEl = this.wrapperEl as HTMLDivElement,
lowerCanvasEl = this.lowerCanvasEl!,
upperCanvasEl = this.upperCanvasEl!,
cacheCanvasEl = this.cacheCanvasEl!;
// @ts-ignore
this.removeListeners();
activeSelection = this._activeSelection!;
// dispose of active selection
activeSelection.removeAll();
(this as TDestroyedCanvas<this>)._activeSelection = undefined;
activeSelection.dispose();
super.destroy();
wrapperEl.removeChild(upperCanvasEl);
wrapperEl.removeChild(lowerCanvasEl);
this.contextCache = null;
this.contextTop = null;
(this as TDestroyedCanvas<this>).pixelFindContext = null;
(this as TDestroyedCanvas<this>).contextTop = null;
// TODO: interactive canvas should NOT be used in node, therefore there is no reason to cleanup node canvas
cleanUpJsdomNode(upperCanvasEl);
this.upperCanvasEl = undefined;
cleanUpJsdomNode(cacheCanvasEl);
this.cacheCanvasEl = undefined;
getEnv().dispose(upperCanvasEl);
(this as TDestroyedCanvas<this>).upperCanvasEl = undefined;
getEnv().dispose(this.pixelFindCanvasEl!);
(this as TDestroyedCanvas<this>).pixelFindCanvasEl = undefined;
if (wrapperEl.parentNode) {
wrapperEl.parentNode.replaceChild(lowerCanvasEl, wrapperEl);
}
this.wrapperEl = undefined;
(this as TDestroyedCanvas<this>).wrapperEl = undefined;
}

@@ -1548,4 +1549,6 @@

clear() {
// this.discardActiveGroup();
// discard active object and fire events
this.discardActiveObject();
// make sure we clear the active object in case it refused to be discarded
this._activeObject = undefined;
this.clearContext(this.contextTop);

@@ -1587,3 +1590,3 @@ super.clear();

/**
* Realises an object's group transformation on it
* Realizes an object's group transformation on it
* @private

@@ -1598,3 +1601,3 @@ * @param {FabricObject} [instance] the object to transform (gets mutated)

instance.group &&
isActiveSelection(instance.group) &&
instance.group === this._activeSelection &&
this._activeObject === instance.group

@@ -1636,32 +1639,1 @@ ) {

}
Object.assign(SelectableCanvas.prototype, {
uniformScaling: true,
uniScaleKey: 'shiftKey',
centeredScaling: false,
centeredRotation: false,
centeredKey: 'altKey',
altActionKey: 'shiftKey',
selection: true,
selectionKey: 'shiftKey',
altSelectionKey: null,
selectionColor: 'rgba(100, 100, 255, 0.3)', // blue
selectionDashArray: [],
selectionBorderColor: 'rgba(255, 255, 255, 0.3)',
selectionLineWidth: 1,
selectionFullyContained: false,
hoverCursor: 'move',
moveCursor: 'move',
defaultCursor: 'default',
freeDrawingCursor: 'crosshair',
notAllowedCursor: 'not-allowed',
containerClass: 'canvas-container',
perPixelTargetFind: false,
targetFindTolerance: 0,
skipTargetFind: false,
preserveObjectStacking: false,
stopContextMenu: false,
fireRightClick: false,
fireMiddleClick: false,
enablePointerEvents: false,
});

@@ -1,2 +0,2 @@

import { getEnv } from '../env';
import { getDocument, getEnv } from '../env';
import { config } from '../config';

@@ -29,3 +29,3 @@ import { iMatrix, VERSION } from '../constants';

} from '../util/animation/AnimationFrameProvider';
import { cleanUpJsdomNode, getElementOffset } from '../util/dom_misc';
import { getElementOffset } from '../util/dom_misc';
import { uid } from '../util/internals/uid';

@@ -44,2 +44,18 @@ import { createCanvasElement, isHTMLCanvas, toDataURL } from '../util/misc/dom';

type TDestroyed<T, K extends keyof any> = {
// @ts-expect-error TS doesn't recognize protected/private fields using the `keyof` directive so we use `keyof any`
[R in K | keyof T]: R extends K ? T[R] | undefined | null : T[R];
};
export type TDestroyedCanvas<T extends StaticCanvas> = TDestroyed<
T,
| 'contextTop'
| 'pixelFindContext'
| 'lowerCanvasEl'
| 'upperCanvasEl'
| 'pixelFindCanvasEl'
| 'wrapperEl'
| '_activeSelection'
>;
const CANVAS_INIT_ERROR = 'Could not initialize `canvas` element';

@@ -70,2 +86,21 @@

export const StaticCanvasDefaults = {
backgroundColor: '',
backgroundImage: null,
overlayColor: '',
overlayImage: null,
includeDefaultValues: true,
renderOnAddRemove: true,
controlsAboveOverlay: false,
allowTouchScrolling: false,
imageSmoothingEnabled: true,
viewportTransform: iMatrix.concat(),
backgroundVpt: true,
overlayVpt: true,
enableRetinaScaling: true,
svgViewportTransformation: true,
skipOffscreen: true,
clipPath: undefined,
};
/**

@@ -274,2 +309,4 @@ * Static canvas class

static ownDefaults: Record<string, any> = StaticCanvasDefaults;
// reference to

@@ -281,4 +318,12 @@ protected declare __cleanupTask?: {

static getDefaults(): Record<string, any> {
return StaticCanvas.ownDefaults;
}
constructor(el: string | HTMLCanvasElement, options = {}) {
super();
Object.assign(
this,
(this.constructor as typeof StaticCanvas).getDefaults()
);
this.set(options);

@@ -405,3 +450,3 @@ this.initElements(el);

this.lowerCanvasEl =
(getEnv().document.getElementById(canvasEl) as HTMLCanvasElement) ||
(getDocument().getElementById(canvasEl) as HTMLCanvasElement) ||
this._createCanvasElement();

@@ -1663,7 +1708,7 @@ }

this._objects = [];
if (this.backgroundImage && this.backgroundImage.dispose) {
if (this.backgroundImage) {
this.backgroundImage.dispose();
}
this.backgroundImage = null;
if (this.overlayImage && this.overlayImage.dispose) {
if (this.overlayImage) {
this.overlayImage.dispose();

@@ -1674,5 +1719,4 @@ }

this.contextContainer = null;
const canvasElement = this.lowerCanvasEl;
// @ts-expect-error disposing
this.lowerCanvasEl = undefined;
const canvasElement = this.lowerCanvasEl!;
(this as TDestroyedCanvas<StaticCanvas>).lowerCanvasEl = undefined;
// restore canvas style and attributes

@@ -1686,3 +1730,3 @@ canvasElement.classList.remove('lower-canvas');

this._originalCanvasStyle = undefined;
cleanUpJsdomNode(canvasElement);
getEnv().dispose(canvasElement);
}

@@ -1700,20 +1744,1 @@

}
Object.assign(StaticCanvas.prototype, {
backgroundColor: '',
backgroundImage: null,
overlayColor: '',
overlayImage: null,
includeDefaultValues: true,
renderOnAddRemove: true,
controlsAboveOverlay: false,
allowTouchScrolling: false,
imageSmoothingEnabled: true,
viewportTransform: iMatrix.concat(),
backgroundVpt: true,
overlayVpt: true,
enableRetinaScaling: true,
svgViewportTransformation: true,
skipOffscreen: true,
clipPath: undefined,
});

@@ -1,4 +0,6 @@

import type { Constructor } from './typedefs';
import type { Constructor, TBBox } from './typedefs';
import type { BaseFabricObject } from './EventTypeDefs';
import { removeFromArray } from './util/internals';
import { Point } from './Point';
import { InteractiveFabricObject } from './shapes/Object/InteractiveObject';

@@ -102,3 +104,3 @@ export function createCollectionMixin<TBase extends Constructor>(Base: TBase) {

}
return this._objects.filter((o) => types.includes(o.type));
return this._objects.filter((o) => o.isType(...types));
}

@@ -308,2 +310,35 @@

}
/**
* Given a bounding box, return all the objects of the collection that are contained in the bounding box.
* If `includeIntersecting` is true, return also the objects that intersect the bounding box as well.
* This is meant to work with selection. Is not a generic method.
* @returns array of objects contained in the bounding box, ordered from top to bottom stacking wise
*/
collectObjects(
{ left, top, width, height }: TBBox,
{ includeIntersecting = true }: { includeIntersecting?: boolean } = {}
) {
const objects: InteractiveFabricObject[] = [],
tl = new Point(left, top),
br = tl.add(new Point(width, height));
// we iterate reverse order to collect top first in case of click.
for (let i = this._objects.length - 1; i >= 0; i--) {
const object = this._objects[i] as unknown as InteractiveFabricObject;
if (
object.selectable &&
object.visible &&
((includeIntersecting && object.intersectsWithRect(tl, br, true)) ||
object.isContainedWithinRect(tl, br, true) ||
(includeIntersecting &&
object.containsPoint(tl, undefined, true)) ||
(includeIntersecting && object.containsPoint(br, undefined, true)))
) {
objects.push(object);
}
}
return objects;
}
}

@@ -310,0 +345,0 @@

@@ -6,2 +6,3 @@ import { TMat2D } from './typedefs';

export const VERSION = version;
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function noop() {}

@@ -8,0 +9,0 @@ export const halfPI = Math.PI / 2;

@@ -9,3 +9,3 @@ /* eslint-disable @typescript-eslint/no-unused-vars */

import { Point } from '../Point';
import type { FabricObject } from '../shapes/Object/Object';
import type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';
import { TDegree, TMat2D } from '../typedefs';

@@ -19,3 +19,3 @@ import { cos } from '../util/misc/cos';

renderSquareControl,
} from './controls.render';
} from './controlRendering';

@@ -186,3 +186,3 @@ export class Control {

eventData: TPointerEvent,
fabricObject: FabricObject,
fabricObject: InteractiveFabricObject,
control: Control

@@ -202,3 +202,3 @@ ): TransformActionHandler | undefined {

eventData: TPointerEvent,
fabricObject: FabricObject,
fabricObject: InteractiveFabricObject,
control: Control

@@ -219,3 +219,3 @@ ): ControlActionHandler | undefined {

eventData: TPointerEvent,
fabricObject: FabricObject,
fabricObject: InteractiveFabricObject,
control: Control

@@ -238,3 +238,3 @@ ): ControlActionHandler | undefined {

control: Control,
fabricObject: FabricObject
fabricObject: InteractiveFabricObject
) {

@@ -254,3 +254,3 @@ return control.cursorStyle;

control: Control,
fabricObject: FabricObject
fabricObject: InteractiveFabricObject
) {

@@ -266,4 +266,3 @@ return control.actionName;

*/
getVisibility(fabricObject: FabricObject, controlKey: string) {
// @ts-expect-error TODO remove directive once fixed
getVisibility(fabricObject: InteractiveFabricObject, controlKey: string) {
return fabricObject._controlsVisibility?.[controlKey] ?? this.visible;

@@ -277,3 +276,7 @@ }

*/
setVisibility(visibility: boolean, name: string, fabricObject: FabricObject) {
setVisibility(
visibility: boolean,
name: string,
fabricObject: InteractiveFabricObject
) {
this.visible = visibility;

@@ -285,3 +288,3 @@ }

finalMatrix: TMat2D,
fabricObject: FabricObject,
fabricObject: InteractiveFabricObject,
currentControl: Control

@@ -362,3 +365,3 @@ ) {

styleOverride: ControlRenderingStyleOverride | undefined,
fabricObject: FabricObject
fabricObject: InteractiveFabricObject
) {

@@ -365,0 +368,0 @@ styleOverride = styleOverride || {};

/* eslint-disable no-restricted-globals */
import { config } from '../config';
import { WebGLProbe } from '../filters/GLProbes/WebGLProbe';
import { TCopyPasteData, TFabricEnv } from './types';

@@ -25,5 +26,8 @@

isTouchSupported,
isLikelyNode: false,
WebGLProbe: new WebGLProbe(),
dispose() {
// noop
},
copyPasteData,
};
};

@@ -0,3 +1,13 @@

/**
* This file is consumed by fabric.
* The `./node` and `./browser` files define the env variable that is used by this module.
* The `./node` module sets the env at import time.
* The `./browser` module is defined to be the default env and doesn't set the env at all.
* This is done in order to support isomorphic usage for browser and node applications
* since window and document aren't defined at time of import in SSR, we can't set env so we avoid it by deferring to the default env.
*/
import { TFabricEnv } from './types';
import { getEnv as getBrowserEnv } from './browser';
import type { DOMWindow } from 'jsdom';

@@ -14,7 +24,2 @@ let env: TFabricEnv;

export const getWindow = (): Window => getEnv().window;
export const setEnvForTests = (window: Window) => {
env.document = window.document;
env.window = window;
};
export const getWindow = (): Window | DOMWindow => getEnv().window;
/* eslint-disable no-restricted-globals */
import type { Canvas as NodeCanvas } from 'canvas';
import { JSDOM } from 'jsdom';
import utils1 from 'jsdom/lib/jsdom/living/generated/utils.js';
import utils2 from 'jsdom/lib/jsdom/utils.js';
// @ts-ignore
import utils from 'jsdom/lib/jsdom/living/generated/utils.js';
import { config } from '../config';
import { NodeGLProbe } from '../filters/GLProbes/NodeGLProbe';
import { setEnv } from './index';
import { TCopyPasteData, TFabricEnv } from './types';
const { implForWrapper: jsdomImplForWrapper } = utils1;
const { Canvas: nodeCanvas } = utils2;
const { implForWrapper: jsdomImplForWrapper } = utils;
const copyPasteData: TCopyPasteData = {};
const { window: virtualWindow } = new JSDOM(
const { window: JSDOMWindow } = new JSDOM(
decodeURIComponent(

@@ -19,31 +20,34 @@ '%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'

{
features: {
FetchExternalResources: ['img'],
},
resources: 'usable',
// needed for `requestAnimationFrame`
pretendToBeVisual: true,
}
);
const fabricDocument = virtualWindow.document;
const fabricWindow = virtualWindow;
const isTouchSupported =
'ontouchstart' in fabricWindow ||
'ontouchstart' in fabricDocument ||
(fabricWindow &&
fabricWindow.navigator &&
fabricWindow.navigator.maxTouchPoints > 0);
config.configure({
devicePixelRatio: fabricWindow.devicePixelRatio || 1,
devicePixelRatio: JSDOMWindow.devicePixelRatio || 1,
});
export const getNodeCanvas = (canvasEl: HTMLCanvasElement) => {
const impl = jsdomImplForWrapper(canvasEl);
return (impl._canvas || impl._image) as NodeCanvas;
};
export const getEnv = (): TFabricEnv => {
return {
document: fabricDocument,
window: fabricWindow,
isTouchSupported,
isLikelyNode: true,
nodeCanvas,
jsdomImplForWrapper,
document: JSDOMWindow.document,
window: JSDOMWindow,
isTouchSupported: false,
WebGLProbe: new NodeGLProbe(),
dispose(element) {
const impl = jsdomImplForWrapper(element);
if (impl) {
impl._image = null;
impl._canvas = null;
// unsure if necessary
impl._currentSrc = null;
impl._attributes = null;
impl._classList = null;
}
},
copyPasteData,

@@ -50,0 +54,0 @@ };

@@ -1,2 +0,3 @@

import type { Canvas } from 'canvas';
import { GLProbe } from '../filters/GLProbes/GLProbe';
import type { DOMWindow } from 'jsdom';

@@ -9,8 +10,7 @@ export type TCopyPasteData = {

document: Document;
window: Window;
window: Window | DOMWindow;
isTouchSupported: boolean;
isLikelyNode: boolean;
nodeCanvas?: Canvas;
jsdomImplForWrapper?: any;
WebGLProbe: GLProbe;
dispose(element: Element): void;
copyPasteData: TCopyPasteData;
};

@@ -85,2 +85,4 @@ import type { Control } from './controls/Control';

};
// @TODO: investigate if this reset is really needed
reset?: boolean;
actionPerformed: boolean;

@@ -87,0 +89,0 @@ };

@@ -0,1 +1,2 @@

import { getEnv } from '../env';
import { createCanvasElement } from '../util/misc/dom';

@@ -10,19 +11,10 @@ import type {

import { isWebGLPipelineState } from './typedefs';
import { WebGLPrecision, webGLProbe } from './WebGLProbe';
import { GLPrecision } from './GLProbes/GLProbe';
import {
highPsourceCode,
identityFragmentShader,
vertexSource,
} from './shaders/baseFilter';
const highPsourceCode = `precision ${WebGLPrecision.high} float`;
export type AbstractBaseFilterOptions<T> = {
mainParameter: string;
vertexSource: string;
fragmentSource: T;
};
export type BaseFilterOptions = AbstractBaseFilterOptions<string>;
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AnyFilter
extends AbstractBaseFilter<string | Record<string, string>> {}
export abstract class AbstractBaseFilter<T> {
export class BaseFilter {
/**

@@ -33,4 +25,8 @@ * Filter type

*/
declare type: string;
get type(): string {
return this.constructor.name;
}
declare static defaults: Record<string, any>;
/**

@@ -40,6 +36,4 @@ * Array of attributes to send with buffers. do not modify

*/
declare vertexSource: string;
vertexSource = vertexSource;
declare fragmentSource: T;
/**

@@ -51,3 +45,3 @@ * Name of the parameter that can be changed in the filter.

*/
declare mainParameter?: keyof this;
declare mainParameter?: keyof this | undefined;

@@ -58,9 +52,13 @@ /**

*/
constructor(
options: Partial<AbstractBaseFilterOptions<T>> & Record<string, any> = {}
) {
Object.assign(this, options);
constructor({ ...options }: Record<string, any> = {}) {
Object.assign(
this,
(this.constructor as typeof BaseFilter).defaults,
options
);
}
abstract getFragmentSource(): string;
protected getFragmentSource(): string {
return identityFragmentShader;
}

@@ -79,9 +77,7 @@ /**

) {
if (
webGLProbe.webGLPrecision &&
webGLProbe.webGLPrecision !== WebGLPrecision.high
) {
const { WebGLProbe } = getEnv();
if (WebGLProbe.GLPrecision && WebGLProbe.GLPrecision !== GLPrecision.high) {
fragmentSource = fragmentSource.replace(
new RegExp(highPsourceCode, 'g'),
highPsourceCode.replace(WebGLPrecision.high, webGLProbe.webGLPrecision)
highPsourceCode.replace(GLPrecision.high, WebGLProbe.GLPrecision)
);

@@ -161,6 +157,8 @@ }

*/
abstract getUniformLocations(
getUniformLocations(
gl: WebGLRenderingContext,
program: WebGLProgram
): TWebGLUniformLocationMap;
): TWebGLUniformLocationMap {
return {};
}

@@ -231,12 +229,13 @@ /**

const main = this.mainParameter,
// @ts-ignore ts you are lying
proto = this.__proto__;
defaultValue = (this.constructor as typeof BaseFilter).defaults[
main as string
];
if (main) {
if (Array.isArray(proto[main]) && Array.isArray(this[main])) {
return proto[main].every(
// @ts-ignore requires some kind of dynamic type thing, or delete, or leave it ignored
(value: any, i: number) => value === this[main][i]
const thisValue = this[main];
if (Array.isArray(defaultValue) && Array.isArray(thisValue)) {
return defaultValue.every(
(value: any, i: number) => value === thisValue[i]
);
} else {
return proto[main] === this[main];
return defaultValue === thisValue;
}

@@ -271,4 +270,11 @@ } else {

abstract applyTo2d(options: T2DPipelineState): void;
applyTo2d(options: T2DPipelineState): void {
// override by subclass
}
/**
* Returns a string that represent the current selected shader code for the filter.
* Used to force recompilation when parameters change or to retrieve the shader from cache
* @type string
**/
getCacheKey() {

@@ -359,6 +365,8 @@ return this.type;

*/
abstract sendUniformData(
sendUniformData(
gl: WebGLRenderingContext,
uniformLocations: TWebGLUniformLocationMap
): void;
): void {
// override by subclass
}

@@ -398,28 +406,9 @@ /**

}
}
export abstract class BaseFilter extends AbstractBaseFilter<string> {
getFragmentSource() {
return this.fragmentSource;
static async fromObject(
{ type, ...filterOptions }: Record<string, any>,
options: { signal: AbortSignal }
) {
return new this(filterOptions);
}
}
Object.assign(AbstractBaseFilter.prototype, {
vertexSource: `
attribute vec2 aPosition;
varying vec2 vTexCoord;
void main() {
vTexCoord = aPosition;
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
}`,
});
Object.assign(BaseFilter.prototype, {
fragmentSource: `
${highPsourceCode};
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
}`,
});
import { Color } from '../color/Color';
import { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { blendColorFragmentSource } from './shaders/blendColor';
type TBlendMode =
| 'multiply'
| 'add'
| 'difference'
| 'screen'
| 'subtract'
| 'darken'
| 'lighten'
| 'overlay'
| 'exclusion'
| 'tint';
export const blendColorDefaultValues: Partial<TClassProperties<BlendColor>> = {
color: '#F95C63',
mode: 'multiply',
alpha: 1,
};
/**

@@ -24,3 +43,3 @@ * Color Blend filter class

*/
export class BlendColor extends AbstractBaseFilter<Record<string, string>> {
export class BlendColor extends BaseFilter {
/**

@@ -34,14 +53,9 @@ * Color to make the blend operation with. default to a reddish color since black or white

declare mode:
| 'multiply'
| 'add'
| 'diff'
| 'difference'
| 'screen'
| 'subtract'
| 'darken'
| 'lighten'
| 'overlay'
| 'exclusion'
| 'tint';
/**
* Blend mode for the filter: one of multiply, add, difference, screen, subtract,
* darken, lighten, overlay, exclusion, tint.
* @type String
* @default
**/
declare mode: TBlendMode;

@@ -55,10 +69,9 @@ /**

/**
* build the fragment source for the filters, joining the common part with
* the specific one.
* @param {String} mode the mode of the filter, a key of this.fragmentSource
* @return {String} the source to be compiled
* @private
*/
buildSource(mode: string) {
static defaults = blendColorDefaultValues;
getCacheKey() {
return `${this.type}_${this.mode}`;
}
protected getFragmentSource(): string {
return `

@@ -73,3 +86,3 @@ precision highp float;

if (color.a > 0.0) {
${this.fragmentSource[mode]}
${blendColorFragmentSource[this.mode]}
}

@@ -80,10 +93,2 @@ }

getCacheKey() {
return `${this.type}_${this.mode}`;
}
getFragmentSource(): string {
return this.buildSource(this.mode);
}
/**

@@ -123,3 +128,2 @@ * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.

break;
case 'diff':
case 'difference':

@@ -217,49 +221,4 @@ data[i] = Math.abs(r - tr);

}
static async fromObject(object: any) {
return new BlendColor(object);
}
}
export const blendColorDefaultValues: Partial<TClassProperties<BlendColor>> = {
type: 'BlendColor',
color: '#F95C63',
mode: 'multiply',
alpha: 1,
fragmentSource: {
multiply: 'gl_FragColor.rgb *= uColor.rgb;\n',
screen:
'gl_FragColor.rgb = 1.0 - (1.0 - gl_FragColor.rgb) * (1.0 - uColor.rgb);\n',
add: 'gl_FragColor.rgb += uColor.rgb;\n',
diff: 'gl_FragColor.rgb = abs(gl_FragColor.rgb - uColor.rgb);\n',
subtract: 'gl_FragColor.rgb -= uColor.rgb;\n',
lighten: 'gl_FragColor.rgb = max(gl_FragColor.rgb, uColor.rgb);\n',
darken: 'gl_FragColor.rgb = min(gl_FragColor.rgb, uColor.rgb);\n',
exclusion:
'gl_FragColor.rgb += uColor.rgb - 2.0 * (uColor.rgb * gl_FragColor.rgb);\n',
overlay: `
if (uColor.r < 0.5) {
gl_FragColor.r *= 2.0 * uColor.r;
} else {
gl_FragColor.r = 1.0 - 2.0 * (1.0 - gl_FragColor.r) * (1.0 - uColor.r);
}
if (uColor.g < 0.5) {
gl_FragColor.g *= 2.0 * uColor.g;
} else {
gl_FragColor.g = 1.0 - 2.0 * (1.0 - gl_FragColor.g) * (1.0 - uColor.g);
}
if (uColor.b < 0.5) {
gl_FragColor.b *= 2.0 * uColor.b;
} else {
gl_FragColor.b = 1.0 - 2.0 * (1.0 - gl_FragColor.b) * (1.0 - uColor.b);
}
`,
tint: `
gl_FragColor.rgb *= (1.0 - uColor.a);
gl_FragColor.rgb += uColor.rgb;
`,
},
};
Object.assign(BlendColor.prototype, blendColorDefaultValues);
classRegistry.setClass(BlendColor);
import { Image } from '../shapes/Image';
import type { TClassProperties } from '../typedefs';
import { createCanvasElement } from '../util/misc/dom';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type {

@@ -11,4 +11,23 @@ T2DPipelineState,

import { WebGLFilterBackend } from './WebGLFilterBackend';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/blendImage';
export type TBlendImageMode = 'multiply' | 'mask';
export const blendImageDefaultValues: Partial<TClassProperties<BlendImage>> = {
mode: 'multiply',
alpha: 1,
vertexSource: `
attribute vec2 aPosition;
varying vec2 vTexCoord;
varying vec2 vTexCoord2;
uniform mat3 uTransformMatrix;
void main() {
vTexCoord = aPosition;
vTexCoord2 = (uTransformMatrix * vec3(aPosition, 1.0)).xy;
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
}
`,
};
/**

@@ -31,3 +50,3 @@ * Image Blend filter class

*/
export class BlendImage extends AbstractBaseFilter<Record<string, string>> {
export class BlendImage extends BaseFilter {
/**

@@ -39,3 +58,3 @@ * Color to make the blend operation with. default to a reddish color since black or white

declare mode: 'multiply' | 'mask';
declare mode: TBlendImageMode;

@@ -48,2 +67,4 @@ /**

static defaults = blendImageDefaultValues;
getCacheKey() {

@@ -54,3 +75,3 @@ return `${this.type}_${this.mode}`;

getFragmentSource(): string {
return this.fragmentSource[this.mode];
return fragmentSource[this.mode];
}

@@ -202,7 +223,8 @@

static fromObject(
object: Record<string, any>,
{ type, image, ...filterOptions }: Record<string, any>,
options: { signal: AbortSignal }
) {
return Image.fromObject(object.image, options).then(
(image) => new BlendImage({ ...object, image })
return Image.fromObject(image, options).then(
(enlivedImage) =>
new this({ ...filterOptions, image: enlivedImage }) as BaseFilter
);

@@ -212,50 +234,2 @@ }

export const blendImageDefaultValues: Partial<TClassProperties<BlendImage>> = {
type: 'BlendImage',
mode: 'multiply',
alpha: 1,
vertexSource: `
attribute vec2 aPosition;
varying vec2 vTexCoord;
varying vec2 vTexCoord2;
uniform mat3 uTransformMatrix;
void main() {
vTexCoord = aPosition;
vTexCoord2 = (uTransformMatrix * vec3(aPosition, 1.0)).xy;
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
}
`,
fragmentSource: {
multiply: `
precision highp float;
uniform sampler2D uTexture;
uniform sampler2D uImage;
uniform vec4 uColor;
varying vec2 vTexCoord;
varying vec2 vTexCoord2;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
vec4 color2 = texture2D(uImage, vTexCoord2);
color.rgba *= color2.rgba;
gl_FragColor = color;
}
`,
mask: `
precision highp float;
uniform sampler2D uTexture;
uniform sampler2D uImage;
uniform vec4 uColor;
varying vec2 vTexCoord;
varying vec2 vTexCoord2;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
vec4 color2 = texture2D(uImage, vTexCoord2);
color.a = color2.a;
gl_FragColor = color;
}
`,
},
};
Object.assign(BlendImage.prototype, blendImageDefaultValues);
classRegistry.setClass(BlendImage);

@@ -10,4 +10,10 @@ import type { TClassProperties } from '../typedefs';

import { isWebGLPipelineState } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/blur';
export const blurDefaultValues: Partial<TClassProperties<Blur>> = {
blur: 0,
mainParameter: 'blur',
};
/**

@@ -36,2 +42,8 @@ * Blur filter class

static defaults = blurDefaultValues;
getFragmentSource(): string {
return fragmentSource;
}
applyTo(options: TWebGLPipelineState | T2DPipelineState) {

@@ -167,39 +179,4 @@ if (isWebGLPipelineState(options)) {

}
static async fromObject(object: any) {
return new Blur(object);
}
}
export const blurDefaultValues: Partial<TClassProperties<Blur>> = {
type: 'Blur',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform vec2 uDelta;
varying vec2 vTexCoord;
const float nSamples = 15.0;
vec3 v3offset = vec3(12.9898, 78.233, 151.7182);
float random(vec3 scale) {
/* use the fragment position for a different seed per-pixel */
return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453);
}
void main() {
vec4 color = vec4(0.0);
float total = 0.0;
float offset = random(v3offset);
for (float t = -nSamples; t <= nSamples; t++) {
float percent = (t + offset - 0.5) / nSamples;
float weight = 1.0 - abs(percent);
color += texture2D(uTexture, vTexCoord + uDelta * percent) * weight;
total += weight;
}
gl_FragColor = color / total;
}
`,
blur: 0,
mainParameter: 'blur',
};
Object.assign(Blur.prototype, blurDefaultValues);
classRegistry.setClass(Blur);

@@ -5,2 +5,7 @@ import { TClassProperties } from '../typedefs';

export const myFilterDefaultValues: Partial<TClassProperties<MyFilter>> = {
myParameter: 0,
mainParameter: 'myParameter',
};
/**

@@ -25,2 +30,17 @@ * MyFilter filter class

static defaults = myFilterDefaultValues;
getFragmentSource() {
return `
precision highp float;
uniform sampler2D uTexture;
uniform float uMyParameter;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
// add your gl code here
gl_FragColor = color;
}
`;
}
/**

@@ -72,23 +92,6 @@ * Apply the MyFilter operation to a Uint8ClampedArray representing the pixels of an image.

static async fromObject(object: any) {
return new MyFilter(object);
// or overide with custom logic if your filter needs to
// deserialize something that is not a plain value
return new this(object) as BaseFilter;
}
}
export const myFilterDefaultValues: Partial<TClassProperties<MyFilter>> = {
type: 'MyFilter',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMyParameter;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
// add your gl code here
gl_FragColor = color;
}
`,
myParameter: 0,
mainParameter: 'myParameter',
};
Object.assign(MyFilter.prototype, myFilterDefaultValues);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/brightness';
export const brightnessDefaultValues: Partial<TClassProperties<Brightness>> = {
brightness: 0,
mainParameter: 'brightness',
};
/**

@@ -24,2 +30,8 @@ * Brightness filter class

static defaults = brightnessDefaultValues;
getFragmentSource() {
return fragmentSource;
}
/**

@@ -70,26 +82,4 @@ * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.

}
static async fromObject(object: any) {
return new Brightness(object);
}
}
export const brightnessDefaultValues: Partial<TClassProperties<Brightness>> = {
type: 'Brightness',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uBrightness;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
color.rgb += uBrightness;
gl_FragColor = color;
}
`,
brightness: 0,
mainParameter: 'brightness',
};
Object.assign(Brightness.prototype, brightnessDefaultValues);
classRegistry.setClass(Brightness);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/colorMatrix';
export const colorMatrixDefaultValues: Partial<TClassProperties<ColorMatrix>> =
{
matrix: [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
mainParameter: 'matrix',
colorsOnly: true,
};
/**

@@ -40,2 +48,4 @@ * Color Matrix filter class

static defaults = colorMatrixDefaultValues;
setOptions({ matrix, ...options }: Record<string, any>) {

@@ -49,2 +59,6 @@ if (matrix) {

getFragmentSource(): string {
return fragmentSource;
}
/**

@@ -131,29 +145,4 @@ * Apply the ColorMatrix operation to a Uint8Array representing the pixels of an image.

}
static async fromObject(object: any) {
return new ColorMatrix(object);
}
}
export const colorMatrixDefaultValues: Partial<TClassProperties<ColorMatrix>> =
{
type: 'ColorMatrix',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
varying vec2 vTexCoord;
uniform mat4 uColorMatrix;
uniform vec4 uConstants;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
color *= uColorMatrix;
color += uConstants;
gl_FragColor = color;
}`,
matrix: [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
mainParameter: 'matrix',
colorsOnly: true,
};
Object.assign(ColorMatrix.prototype, colorMatrixDefaultValues);
classRegistry.setClass(ColorMatrix);

@@ -1,36 +0,21 @@

import { ColorMatrix } from './ColorMatrix';
import { classRegistry } from '../util/class_registry';
import { ColorMatrix, colorMatrixDefaultValues } from './ColorMatrix';
import { classRegistry } from '../ClassRegistry';
export function createColorMatrixFilter(key: string, matrix: number[]) {
return class GeneratedColorMatrix extends ColorMatrix {
/**
* Filter type
* @param {String} type
* @default
*/
type = key;
const newClass = class extends ColorMatrix {
get type() {
return key;
}
/**
* Colormatrix for the effect
* array of 20 floats. Numbers in positions 4, 9, 14, 19 loose meaning
* outside the -1, 1 range.
* @param {Array} matrix array of 20 numbers.
* @default
*/
matrix = matrix;
/**
* Lock the matrix export for this kind of static, parameter less filters.
*/
mainParameter = undefined;
/**
* Lock the colormatrix on the color part, skipping alpha
*/
colorsOnly = true;
static async fromObject(object: any) {
return new GeneratedColorMatrix(object);
}
static defaults = {
...colorMatrixDefaultValues,
/**
* Lock the matrix export for this kind of static, parameter less filters.
*/
mainParameter: undefined,
matrix,
};
};
classRegistry.setClass(newClass, key);
return newClass;
}

@@ -46,4 +31,2 @@

classRegistry.setClass(Brownie);
export const Vintage = createColorMatrixFilter(

@@ -57,4 +40,2 @@ 'Vintage',

classRegistry.setClass(Vintage);
export const Kodachrome = createColorMatrixFilter(

@@ -68,4 +49,2 @@ 'Kodachrome',

classRegistry.setClass(Kodachrome);
export const Technicolor = createColorMatrixFilter(

@@ -79,4 +58,2 @@ 'Technicolor',

classRegistry.setClass(Technicolor);
export const Polaroid = createColorMatrixFilter(

@@ -90,4 +67,2 @@ 'Polaroid',

classRegistry.setClass(Polaroid);
export const Sepia = createColorMatrixFilter(

@@ -101,4 +76,2 @@ 'Sepia',

classRegistry.setClass(Sepia);
export const BlackWhite = createColorMatrixFilter(

@@ -111,3 +84,1 @@ 'BlackWhite',

);
classRegistry.setClass(BlackWhite);

@@ -1,10 +0,5 @@

import type { TClassProperties } from '../typedefs';
import {
type AnyFilter,
BaseFilter,
type BaseFilterOptions,
} from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLPipelineState } from './typedefs';
import { isWebGLPipelineState } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';

@@ -14,3 +9,2 @@ /**

*/
// @ts-expect-error
export class Composed extends BaseFilter {

@@ -20,3 +14,3 @@ /**

*/
declare subFilters: AnyFilter[];
declare subFilters: BaseFilter[];

@@ -26,3 +20,3 @@ constructor({

...options
}: Partial<BaseFilterOptions & { subFilters: AnyFilter[] }> = {}) {
}: { subFilters?: BaseFilter[] } & Record<string, any> = {}) {
super(options);

@@ -76,14 +70,11 @@ this.subFilters = subFilters;

return Promise.all(
((object.subFilters || []) as AnyFilter[]).map((filter) =>
((object.subFilters || []) as BaseFilter[]).map((filter) =>
classRegistry.getClass(filter.type).fromObject(filter, options)
)
).then((enlivedFilters) => new Composed({ subFilters: enlivedFilters }));
).then(
(enlivedFilters) => new this({ subFilters: enlivedFilters }) as BaseFilter
);
}
}
export const composedDefaultValues: Partial<TClassProperties<Composed>> = {
type: 'Composed',
};
Object.assign(Composed.prototype, composedDefaultValues);
classRegistry.setClass(Composed);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/constrast';
export const contrastDefaultValues: Partial<TClassProperties<Contrast>> = {
contrast: 0,
mainParameter: 'contrast',
};

@@ -23,2 +28,7 @@ /**

static defaults = contrastDefaultValues;
getFragmentSource() {
return fragmentSource;
}
/**

@@ -71,26 +81,4 @@ * Apply the Contrast operation to a Uint8Array representing the pixels of an image.

}
static async fromObject(object: any) {
return new Contrast(object);
}
}
export const contrastDefaultValues: Partial<TClassProperties<Contrast>> = {
type: 'Contrast',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uContrast;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
float contrastF = 1.015 * (uContrast + 1.0) / (1.0 * (1.015 - uContrast));
color.rgb = contrastF * (color.rgb - 0.5) + 0.5;
gl_FragColor = color;
}`,
contrast: 0,
mainParameter: 'contrast',
};
Object.assign(Contrast.prototype, contrastDefaultValues);
classRegistry.setClass(Contrast);
import type { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/convolute';
export const convoluteDefaultValues: Partial<TClassProperties<Convolute>> = {
opaque: false,
matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0],
};
/**

@@ -46,3 +52,3 @@ * Adapted from <a href="http://www.html5rocks.com/en/tutorials/canvas/imagefilters/">html5rocks article</a>

*/
export class Convolute extends AbstractBaseFilter<Record<string, string>> {
export class Convolute extends BaseFilter {
/*

@@ -58,10 +64,12 @@ * Opaque value (true/false)

static defaults = convoluteDefaultValues;
getCacheKey() {
return `${this.type}_${Math.sqrt(this.matrix.length)}_${
this.opaque ? 1 : 0
}`;
}` as keyof typeof fragmentSource;
}
getFragmentSource() {
return this.fragmentSource[this.getCacheKey()];
return fragmentSource[this.getCacheKey()];
}

@@ -176,169 +184,4 @@

}
static async fromObject(object: any) {
return new Convolute(object);
}
}
export const convoluteDefaultValues: Partial<TClassProperties<Convolute>> = {
type: 'Convolute',
opaque: false,
matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0],
fragmentSource: {
Convolute_3_1: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[9];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 0);
for (float h = 0.0; h < 3.0; h+=1.0) {
for (float w = 0.0; w < 3.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 1), uStepH * (h - 1));
color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 3.0 + w)];
}
}
gl_FragColor = color;
}
`,
Convolute_3_0: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[9];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 1);
for (float h = 0.0; h < 3.0; h+=1.0) {
for (float w = 0.0; w < 3.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 1.0), uStepH * (h - 1.0));
color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 3.0 + w)];
}
}
float alpha = texture2D(uTexture, vTexCoord).a;
gl_FragColor = color;
gl_FragColor.a = alpha;
}
`,
Convolute_5_1: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[25];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 0);
for (float h = 0.0; h < 5.0; h+=1.0) {
for (float w = 0.0; w < 5.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));
color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 5.0 + w)];
}
}
gl_FragColor = color;
}
`,
Convolute_5_0: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[25];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 1);
for (float h = 0.0; h < 5.0; h+=1.0) {
for (float w = 0.0; w < 5.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));
color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 5.0 + w)];
}
}
float alpha = texture2D(uTexture, vTexCoord).a;
gl_FragColor = color;
gl_FragColor.a = alpha;
}
`,
Convolute_7_1: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[49];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 0);
for (float h = 0.0; h < 7.0; h+=1.0) {
for (float w = 0.0; w < 7.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));
color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 7.0 + w)];
}
}
gl_FragColor = color;
}
`,
Convolute_7_0: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[49];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 1);
for (float h = 0.0; h < 7.0; h+=1.0) {
for (float w = 0.0; w < 7.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));
color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 7.0 + w)];
}
}
float alpha = texture2D(uTexture, vTexCoord).a;
gl_FragColor = color;
gl_FragColor.a = alpha;
}
`,
Convolute_9_1: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[81];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 0);
for (float h = 0.0; h < 9.0; h+=1.0) {
for (float w = 0.0; w < 9.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));
color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 9.0 + w)];
}
}
gl_FragColor = color;
}
`,
Convolute_9_0: `
precision highp float;
uniform sampler2D uTexture;
uniform float uMatrix[81];
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
vec4 color = vec4(0, 0, 0, 1);
for (float h = 0.0; h < 9.0; h+=1.0) {
for (float w = 0.0; w < 9.0; w+=1.0) {
vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));
color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 9.0 + w)];
}
}
float alpha = texture2D(uTexture, vTexCoord).a;
gl_FragColor = color;
gl_FragColor.a = alpha;
}
`,
},
};
Object.assign(Convolute.prototype, convoluteDefaultValues);
classRegistry.setClass(Convolute);
import { config } from '../config';
import { getEnv } from '../env';
import { createCanvasElement } from '../util/misc/dom';
import { Canvas2dFilterBackend } from './Canvas2dFilterBackend';
import { WebGLFilterBackend } from './WebGLFilterBackend';
import { webGLProbe } from './WebGLProbe';

@@ -14,4 +15,5 @@ export type FilterBackend = WebGLFilterBackend | Canvas2dFilterBackend;

export function initFilterBackend(): FilterBackend {
webGLProbe.queryWebGL();
if (config.enableGLFiltering && webGLProbe.isSupported(config.textureSize)) {
const { WebGLProbe } = getEnv();
WebGLProbe.queryWebGL(createCanvasElement());
if (config.enableGLFiltering && WebGLProbe.isSupported(config.textureSize)) {
return new WebGLFilterBackend({ tileSize: config.textureSize });

@@ -24,3 +26,3 @@ } else {

/**
* Get the current fabricJS filter backend or initialize one if not avaialble yet
* Get the current fabricJS filter backend or initialize one if not available yet
* @param [strict] pass `true` to create the backend if it wasn't created yet (default behavior),

@@ -27,0 +29,0 @@ * pass `false` to get the backend ref without mutating it

import type { TClassProperties } from '../typedefs';
import { BaseFilter, BaseFilterOptions } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/gamma';
export type GammaInput = [number, number, number];
export const gammaDefaultValues: Partial<TClassProperties<Gamma>> = {
mainParameter: 'gamma',
gamma: [1, 1, 1],
};
/**

@@ -30,8 +35,11 @@ * Gamma filter class

constructor({
gamma,
...options
}: Partial<BaseFilterOptions> & { gamma?: GammaInput } = {}) {
static defaults = gammaDefaultValues;
getFragmentSource() {
return fragmentSource;
}
constructor({ gamma = [1, 1, 1], ...options }: { gamma?: GammaInput } = {}) {
super(options);
this.gamma = gamma || [1, 1, 1];
this.gamma = gamma;
}

@@ -61,11 +69,12 @@

// instead of performing these pow calls for each pixel in the image.
const rgb = this.rgbValues;
for (let i = 0; i < 256; i++) {
this.rgbValues.r[i] = Math.pow(i / 255, rInv) * 255;
this.rgbValues.g[i] = Math.pow(i / 255, gInv) * 255;
this.rgbValues.b[i] = Math.pow(i / 255, bInv) * 255;
rgb.r[i] = Math.pow(i / 255, rInv) * 255;
rgb.g[i] = Math.pow(i / 255, gInv) * 255;
rgb.b[i] = Math.pow(i / 255, bInv) * 255;
}
for (let i = 0; i < data.length; i += 4) {
data[i] = this.rgbValues.r[data[i]];
data[i + 1] = this.rgbValues.g[data[i + 1]];
data[i + 2] = this.rgbValues.b[data[i + 2]];
data[i] = rgb.r[data[i]];
data[i + 1] = rgb.g[data[i + 1]];
data[i + 2] = rgb.b[data[i + 2]];
}

@@ -101,30 +110,4 @@ }

}
static async fromObject(object: any) {
return new Gamma(object);
}
}
export const gammaDefaultValues: Partial<TClassProperties<Gamma>> = {
type: 'Gamma',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform vec3 uGamma;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
vec3 correction = (1.0 / uGamma);
color.r = pow(color.r, correction.r);
color.g = pow(color.g, correction.g);
color.b = pow(color.b, correction.b);
gl_FragColor = color;
gl_FragColor.rgb *= color.a;
}
`,
mainParameter: 'gamma',
gamma: [1, 1, 1],
};
Object.assign(Gamma.prototype, gammaDefaultValues);
classRegistry.setClass(Gamma);
import type { TClassProperties } from '../typedefs';
import { AbstractBaseFilter } from './BaseFilter';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/grayscale';
export type TGrayscaleMode = 'average' | 'lightness' | 'luminosity';
export const grayscaleDefaultValues: Partial<TClassProperties<Grayscale>> = {
mode: 'average',
mainParameter: 'mode',
};
/**

@@ -13,5 +21,7 @@ * Grayscale image filter class

*/
export class Grayscale extends AbstractBaseFilter<Record<string, string>> {
declare mode: 'average' | 'lightness' | 'luminosity';
export class Grayscale extends BaseFilter {
declare mode: TGrayscaleMode;
static defaults = grayscaleDefaultValues;
/**

@@ -51,3 +61,3 @@ * Apply the Grayscale operation to a Uint8Array representing the pixels of an image.

getFragmentSource() {
return this.fragmentSource[this.mode];
return fragmentSource[this.mode];
}

@@ -92,49 +102,4 @@

}
static async fromObject(object: any) {
return new Grayscale(object);
}
}
export const grayscaleDefaultValues: Partial<TClassProperties<Grayscale>> = {
type: 'Grayscale',
fragmentSource: {
average: `
precision highp float;
uniform sampler2D uTexture;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
float average = (color.r + color.b + color.g) / 3.0;
gl_FragColor = vec4(average, average, average, color.a);
}
`,
lightness: `
precision highp float;
uniform sampler2D uTexture;
uniform int uMode;
varying vec2 vTexCoord;
void main() {
vec4 col = texture2D(uTexture, vTexCoord);
float average = (max(max(col.r, col.g),col.b) + min(min(col.r, col.g),col.b)) / 2.0;
gl_FragColor = vec4(average, average, average, col.a);
}
`,
luminosity: `
precision highp float;
uniform sampler2D uTexture;
uniform int uMode;
varying vec2 vTexCoord;
void main() {
vec4 col = texture2D(uTexture, vTexCoord);
float average = 0.21 * col.r + 0.72 * col.g + 0.07 * col.b;
gl_FragColor = vec4(average, average, average, col.a);
}
`,
},
mode: 'average',
mainParameter: 'mode',
};
Object.assign(Grayscale.prototype, grayscaleDefaultValues);
classRegistry.setClass(Grayscale);

@@ -6,4 +6,10 @@ import type { TClassProperties } from '../typedefs';

import type { TWebGLPipelineState, T2DPipelineState } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
export const hueRotationDefaultValues: Partial<TClassProperties<HueRotation>> =
{
rotation: 0,
mainParameter: 'rotation',
};
/**

@@ -18,3 +24,3 @@ * HueRotation filter class

*/
// @ts-expect-error fromObject
// @ts-expect-error some babbling about mainParameter
export class HueRotation extends ColorMatrix {

@@ -26,2 +32,4 @@ /**

static defaults = hueRotationDefaultValues;
calculateMatrix() {

@@ -55,16 +63,4 @@ const rad = this.rotation * Math.PI,

}
static async fromObject(object: any) {
return new HueRotation(object);
}
}
export const hueRotationDefaultValues: Partial<TClassProperties<HueRotation>> =
{
type: 'HueRotation',
rotation: 0,
mainParameter: 'rotation',
};
Object.assign(HueRotation.prototype, hueRotationDefaultValues);
classRegistry.setClass(HueRotation);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/invert';
export const invertDefaultValues: Partial<TClassProperties<Invert>> = {
alpha: false,
invert: true,
mainParameter: 'invert',
};
/**

@@ -27,2 +34,4 @@ * @example

static defaults = invertDefaultValues;
/**

@@ -46,2 +55,6 @@ * Apply the Invert operation to a Uint8Array representing the pixels of an image.

protected getFragmentSource(): string {
return fragmentSource;
}
/**

@@ -86,35 +99,4 @@ * Invert filter isNeutralState implementation

}
static async fromObject(object: any) {
return new Invert(object);
}
}
export const invertDefaultValues: Partial<TClassProperties<Invert>> = {
type: 'Invert',
alpha: false,
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform int uInvert;
uniform int uAlpha;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
if (uInvert == 1) {
if (uAlpha == 1) {
gl_FragColor = vec4(1.0 - color.r,1.0 -color.g,1.0 -color.b,1.0 -color.a);
} else {
gl_FragColor = vec4(1.0 - color.r,1.0 -color.g,1.0 -color.b,color.a);
}
} else {
gl_FragColor = color;
}
}
`,
invert: true,
mainParameter: 'invert',
};
Object.assign(Invert.prototype, invertDefaultValues);
classRegistry.setClass(Invert);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/noise';
export const noiseDefaultValues: Partial<TClassProperties<Noise>> = {
mainParameter: 'noise',
noise: 0,
};
/**

@@ -24,2 +30,8 @@ * Noise filter class

static defaults = noiseDefaultValues;
getFragmentSource() {
return fragmentSource;
}
/**

@@ -81,31 +93,4 @@ * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.

}
static async fromObject(object: any) {
return new Noise(object);
}
}
export const noiseDefaultValues: Partial<TClassProperties<Noise>> = {
type: 'Noise',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uStepH;
uniform float uNoise;
uniform float uSeed;
varying vec2 vTexCoord;
float rand(vec2 co, float seed, float vScale) {
return fract(sin(dot(co.xy * vScale ,vec2(12.9898 , 78.233))) * 43758.5453 * (seed + 0.01) / 2.0);
}
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
color.rgb += (0.5 - rand(vTexCoord, uSeed, 0.1 / uStepH)) * uNoise;
gl_FragColor = color;
}
`,
mainParameter: 'noise',
noise: 0,
};
Object.assign(Noise.prototype, noiseDefaultValues);
classRegistry.setClass(Noise);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/pixelate';
export const pixelateDefaultValues: Partial<TClassProperties<Pixelate>> = {
blocksize: 4,
mainParameter: 'blocksize',
};
/**

@@ -18,2 +24,4 @@ * Pixelate filter class

static defaults = pixelateDefaultValues;
/**

@@ -54,2 +62,6 @@ * Apply the Pixelate operation to a Uint8ClampedArray representing the pixels of an image.

protected getFragmentSource(): string {
return fragmentSource;
}
/**

@@ -84,34 +96,4 @@ * Return WebGL uniform locations for this filter's shader.

}
static async fromObject(object: any) {
return new Pixelate(object);
}
}
export const pixelateDefaultValues: Partial<TClassProperties<Pixelate>> = {
type: 'Pixelate',
blocksize: 4,
mainParameter: 'blocksize',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uBlocksize;
uniform float uStepW;
uniform float uStepH;
varying vec2 vTexCoord;
void main() {
float blockW = uBlocksize * uStepW;
float blockH = uBlocksize * uStepW;
int posX = int(vTexCoord.x / blockW);
int posY = int(vTexCoord.y / blockH);
float fposX = float(posX);
float fposY = float(posY);
vec2 squareCoords = vec2(fposX * blockW, fposY * blockH);
vec4 color = texture2D(uTexture, squareCoords);
gl_FragColor = color;
}
`,
};
Object.assign(Pixelate.prototype, pixelateDefaultValues);
classRegistry.setClass(Pixelate);

@@ -5,3 +5,10 @@ import { Color } from '../color/Color';

import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentShader } from './shaders/removeColor';
export const removeColorDefaultValues: Partial<TClassProperties<RemoveColor>> =
{
color: '#FFFFFF',
distance: 0.02,
useAlpha: false,
};

@@ -38,2 +45,8 @@ /**

static defaults = removeColorDefaultValues;
getFragmentShader() {
return fragmentShader;
}
/**

@@ -122,30 +135,4 @@ * Applies filter to canvas element

}
static async fromObject(object: any) {
return new RemoveColor(object);
}
}
export const removeColorDefaultValues: Partial<TClassProperties<RemoveColor>> =
{
type: 'RemoveColor',
color: '#FFFFFF',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform vec4 uLow;
uniform vec4 uHigh;
varying vec2 vTexCoord;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
if(all(greaterThan(gl_FragColor.rgb,uLow.rgb)) && all(greaterThan(uHigh.rgb,gl_FragColor.rgb))) {
gl_FragColor.a = 0.0;
}
}
`,
distance: 0.02,
useAlpha: false,
};
Object.assign(RemoveColor.prototype, removeColorDefaultValues);
classRegistry.setClass(RemoveColor);
// @ts-nocheck
import { getEnv } from '../env';
import type { TClassProperties } from '../typedefs';

@@ -7,4 +6,20 @@ import { BaseFilter } from './BaseFilter';

import { isWebGLPipelineState } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { createCanvasElement } from '../util/misc/dom';
export const resizeDefaultValues: Partial<TClassProperties<Resize>> = {
resizeType: 'hermite',
scaleX: 1,
scaleY: 1,
lanczosLobes: 3,
fragmentSourceTOP: `
precision highp float;
uniform sampler2D uTexture;
uniform vec2 uDelta;
varying vec2 vTexCoord;
`,
};
type TResizeType = 'bilinear' | 'hermite' | 'sliceHack' | 'lanczos';
/**

@@ -24,3 +39,3 @@ * Resize image filter class

*/
declare resizeType: 'bilinear' | 'hermite' | 'sliceHack' | 'lanczos';
declare resizeType: TResizeType;

@@ -50,2 +65,4 @@ /**

static defaults = resizeDefaultValues;
/**

@@ -200,7 +217,7 @@ * Return WebGL uniform locations for this filter's shader.

let oW = imageData.width,
oH = imageData.height,
dW = Math.round(oW * scaleX),
dH = Math.round(oH * scaleY),
newData;
const oW = imageData.width;
const oH = imageData.height;
const dW = Math.round(oW * scaleX);
const dH = Math.round(oH * scaleY);
let newData;

@@ -235,15 +252,15 @@ if (this.resizeType === 'sliceHack') {

) {
let imageData = options.imageData,
mult = 0.5,
doneW = false,
doneH = false,
stepW = oW * mult,
stepH = oH * mult,
resources = options.filterBackend.resources,
sX = 0,
sY = 0,
dX = oW,
dY = 0;
const imageData = options.imageData;
const mult = 0.5;
let doneW = false;
let doneH = false;
let stepW = oW * mult;
let stepH = oH * mult;
const resources = options.filterBackend.resources;
let sX = 0;
let sY = 0;
const dX = oW;
let dY = 0;
if (!resources.sliceByTwo) {
resources.sliceByTwo = getEnv().document.createElement('canvas');
resources.sliceByTwo = createCanvasElement();
}

@@ -391,23 +408,23 @@ const tmpCanvas = resources.sliceByTwo;

) {
let a,
b,
c,
d,
x,
y,
i,
j,
xDiff,
yDiff,
chnl,
color,
offset = 0,
origPix,
ratioX = this.rcpScaleX,
ratioY = this.rcpScaleY,
w4 = 4 * (oW - 1),
img = options.imageData,
pixels = img.data,
destImage = options.ctx.createImageData(dW, dH),
destPixels = destImage.data;
let a;
let b;
let c;
let d;
let x;
let y;
let i;
let j;
let xDiff;
let yDiff;
let chnl;
let color;
let offset = 0;
let origPix;
const ratioX = this.rcpScaleX;
const ratioY = this.rcpScaleY;
const w4 = 4 * (oW - 1);
const img = options.imageData;
const pixels = img.data;
const destImage = options.ctx.createImageData(dW, dH);
const destPixels = destImage.data;
for (i = 0; i < dH; i++) {

@@ -464,11 +481,11 @@ for (j = 0; j < dW; j++) {

for (let i = 0; i < dW; i++) {
let x2 = (i + j * dW) * 4,
weight = 0,
weights = 0,
weightsAlpha = 0,
gxR = 0,
gxG = 0,
gxB = 0,
gxA = 0,
centerY = (j + 0.5) * ratioH;
const x2 = (i + j * dW) * 4;
let weight = 0;
let weights = 0;
let weightsAlpha = 0;
let gxR = 0;
let gxG = 0;
let gxB = 0;
let gxA = 0;
const centerY = (j + 0.5) * ratioH;
for (let yy = Math.floor(j * ratioH); yy < (j + 1) * ratioH; yy++) {

@@ -479,4 +496,4 @@ const dy = Math.abs(centerY - (yy + 0.5)) / ratioHHalf,

for (let xx = Math.floor(i * ratioW); xx < (i + 1) * ratioW; xx++) {
let dx = Math.abs(centerX - (xx + 0.5)) / ratioWHalf,
w = Math.sqrt(w0 + dx * dx);
let dx = Math.abs(centerX - (xx + 0.5)) / ratioWHalf;
const w = Math.sqrt(w0 + dx * dx);
/* eslint-disable max-depth */

@@ -527,23 +544,4 @@ if (w > 1 && w < -1) {

}
static async fromObject(object: any) {
return new Resize(object);
}
}
export const resizeDefaultValues: Partial<TClassProperties<Resize>> = {
type: 'Resize',
resizeType: 'hermite',
scaleX: 1,
scaleY: 1,
lanczosLobes: 3,
fragmentSourceTOP: `
precision highp float;
uniform sampler2D uTexture;
uniform vec2 uDelta;
varying vec2 vTexCoord;
`,
};
Object.assign(Resize.prototype, resizeDefaultValues);
classRegistry.setClass(Resize);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/saturation';

@@ -15,2 +16,8 @@ /**

*/
export const saturationDefaultValues: Partial<TClassProperties<Saturation>> = {
saturation: 0,
mainParameter: 'saturation',
};
export class Saturation extends BaseFilter {

@@ -27,2 +34,8 @@ /**

static defaults = saturationDefaultValues;
getFragmentSource() {
return fragmentSource;
}
/**

@@ -74,30 +87,4 @@ * Apply the Saturation operation to a Uint8ClampedArray representing the pixels of an image.

}
static async fromObject(object: any) {
return new Saturation(object);
}
}
export const saturationDefaultValues: Partial<TClassProperties<Saturation>> = {
type: 'Saturation',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uSaturation;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
float rgMax = max(color.r, color.g);
float rgbMax = max(rgMax, color.b);
color.r += rgbMax != color.r ? (rgbMax - color.r) * uSaturation : 0.00;
color.g += rgbMax != color.g ? (rgbMax - color.g) * uSaturation : 0.00;
color.b += rgbMax != color.b ? (rgbMax - color.b) * uSaturation : 0.00;
gl_FragColor = color;
}
`,
saturation: 0,
mainParameter: 'saturation',
};
Object.assign(Saturation.prototype, saturationDefaultValues);
classRegistry.setClass(Saturation);
import type { TClassProperties } from '../typedefs';
import { BaseFilter } from './BaseFilter';
import type { T2DPipelineState, TWebGLUniformLocationMap } from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { fragmentSource } from './shaders/vibrance';
export const vibranceDefaultValues: Partial<TClassProperties<Vibrance>> = {
vibrance: 0,
mainParameter: 'vibrance',
};
/**

@@ -26,2 +32,8 @@ * Vibrance filter class

static defaults = vibranceDefaultValues;
getFragmentSource() {
return fragmentSource;
}
/**

@@ -75,31 +87,4 @@ * Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.

}
static async fromObject(object: any) {
return new Vibrance(object);
}
}
export const vibranceDefaultValues: Partial<TClassProperties<Vibrance>> = {
type: 'Vibrance',
fragmentSource: `
precision highp float;
uniform sampler2D uTexture;
uniform float uVibrance;
varying vec2 vTexCoord;
void main() {
vec4 color = texture2D(uTexture, vTexCoord);
float max = max(color.r, max(color.g, color.b));
float avg = (color.r + color.g + color.b) / 3.0;
float amt = (abs(max - avg) * 2.0) * uVibrance;
color.r += max != color.r ? (max - color.r) * amt : 0.00;
color.g += max != color.g ? (max - color.g) * amt : 0.00;
color.b += max != color.b ? (max - color.b) * amt : 0.00;
gl_FragColor = color;
}
`,
vibrance: 0,
mainParameter: 'vibrance',
};
Object.assign(Vibrance.prototype, vibranceDefaultValues);
classRegistry.setClass(Vibrance);

@@ -1,2 +0,2 @@

import { getEnv } from '../env';
import { getWindow } from '../env';
import { config } from '../config';

@@ -100,9 +100,9 @@ import { createCanvasElement } from '../util/misc/dom';

startTime = getEnv().window.performance.now();
startTime = getWindow().performance.now();
this.copyGLTo2D.call(testContext, this.gl, testPipelineState);
const drawImageTime = getEnv().window.performance.now() - startTime;
const drawImageTime = getWindow().performance.now() - startTime;
startTime = getEnv().window.performance.now();
startTime = getWindow().performance.now();
copyGLTo2DPutImageData.call(testContext, this.gl, testPipelineState);
const putImageDataTime = getEnv().window.performance.now() - startTime;
const putImageDataTime = getWindow().performance.now() - startTime;

@@ -109,0 +109,0 @@ if (drawImageTime > putImageDataTime) {

@@ -6,2 +6,3 @@ //@ts-nocheck

import type { FabricObject } from '../shapes/Object/FabricObject';
import { FabricObject as BaseFabricObject } from '../shapes/Object/Object';
import { TMat2D } from '../typedefs';

@@ -26,3 +27,3 @@ import { uid } from '../util/internals/uid';

} from './typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';

@@ -205,3 +206,7 @@ /**

}
if (object.type === 'path' && this.gradientUnits !== 'percentage') {
if (
object instanceof BaseFabricObject &&
object.isType('Path') &&
this.gradientUnits !== 'percentage'
) {
offsetX -= object.pathOffset.x;

@@ -208,0 +213,0 @@ offsetY -= object.pathOffset.y;

import { Color } from '../../color/Color';
import { parsePercent } from '../../parser/percent';
import { ifNaN } from '../../util/internals';
import { ColorStop } from '../typedefs';

@@ -48,3 +49,3 @@ const RE_KEY_VALUE_PAIRS = /\s*;\s*/;

) {
const colorStops = [],
const colorStops: ColorStop[] = [],
colorStopEls = el.getElementsByTagName('stop'),

@@ -51,0 +52,0 @@ multiplier = parsePercent(opacityAttr, 1);

import { Point } from './Point';
import { createVector } from './util/misc/vectors';

@@ -7,18 +8,2 @@ /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */

/**
* **Assuming `T`, `A`, `B` are points on the same line**,
* check if `T` is contained in `[A, B]` by comparing the direction of the vectors from `T` to `A` and `B`
* @param T
* @param A
* @param B
* @returns true if `T` is contained
*/
const isContainedInInterval = (T: Point, A: Point, B: Point) => {
const TA = new Point(T).subtract(A);
const TB = new Point(T).subtract(B);
return (
Math.sign(TA.x) !== Math.sign(TB.x) || Math.sign(TA.y) !== Math.sign(TB.y)
);
};
export class Intersection {

@@ -59,3 +44,47 @@ declare points: Point[];

/**
* check if point T is on the segment or line defined between A and B
*
* @param {Point} T the point we are checking for
* @param {Point} A one extremity of the segment
* @param {Point} B the other extremity of the segment
* @param [infinite] if true checks if `T` is on the line defined by `A` and `B`
* @returns true if `T` is contained
*/
static isPointContained(T: Point, A: Point, B: Point, infinite = false) {
if (A.eq(B)) {
// Edge case: the segment is a point, we check for coincidence,
// infinite param has no meaning because there are infinite lines to consider
return T.eq(A);
} else if (A.x === B.x) {
// Edge case: horizontal line.
// we first check if T.x has the same value, and then if T.y is contained between A.y and B.y
return (
T.x === A.x &&
(infinite || (T.y >= Math.min(A.y, B.y) && T.y <= Math.max(A.y, B.y)))
);
} else if (A.y === B.y) {
// Edge case: vertical line.
// we first check if T.y has the same value, and then if T.x is contained between A.x and B.x
return (
T.y === A.y &&
(infinite || (T.x >= Math.min(A.x, B.x) && T.x <= Math.max(A.x, B.x)))
);
} else {
// Generic case: sloped line.
// we check that AT has the same slope as AB
// for the segment case we need both the vectors to have the same direction and for AT to be lte AB in size
// for the infinite case we check the absolute value of the slope, since direction is meaningless
const AB = createVector(A, B);
const AT = createVector(A, T);
const s = AT.divide(AB);
return infinite
? Math.abs(s.x) === Math.abs(s.y)
: s.x === s.y && s.x >= 0 && s.x <= 1;
}
}
/**
* Checks if a line intersects another
* @see {@link https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection line intersection}
* @see {@link https://en.wikipedia.org/wiki/Cramer%27s_rule Cramer's rule}
* @static

@@ -78,8 +107,8 @@ * @param {Point} a1

): Intersection {
const b2xb1x = b2.x - b1.x,
a1yb1y = a1.y - b1.y,
const a2xa1x = a2.x - a1.x,
a2ya1y = a2.y - a1.y,
b2xb1x = b2.x - b1.x,
b2yb1y = b2.y - b1.y,
a1xb1x = a1.x - b1.x,
a2ya1y = a2.y - a1.y,
a2xa1x = a2.x - a1.x,
a1yb1y = a1.y - b1.y,
uaT = b2xb1x * a1yb1y - b2yb1y * a1xb1x,

@@ -106,6 +135,6 @@ ubT = a2xa1x * a1yb1y - a2ya1y * a1xb1x,

bInfinite ||
isContainedInInterval(a1, b1, b2) ||
isContainedInInterval(a2, b1, b2) ||
isContainedInInterval(b1, a1, a2) ||
isContainedInInterval(b2, a1, a2);
Intersection.isPointContained(a1, b1, b2) ||
Intersection.isPointContained(a2, b1, b2) ||
Intersection.isPointContained(b1, a1, a2) ||
Intersection.isPointContained(b2, a1, a2);
return new Intersection(segmentsCoincide ? 'Coincident' : undefined);

@@ -228,3 +257,3 @@ } else {

length = points1.length;
const coincidences = [];
const coincidences: Intersection[] = [];

@@ -231,0 +260,0 @@ for (let i = 0; i < length; i++) {

@@ -126,10 +126,16 @@ export type TEventCallback<T = any> = (options: T) => any;

/**
* Stops event observing for a particular event handler. Calling this method
* without arguments removes all handlers for all events
* @param {string} eventName Event name (eg. 'after:render')
* @param {EventRegistryObject} handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {Function} handler Function to be deleted from EventListeners
* unsubscribe an event listener
* @param {string} eventName event name (eg. 'after:render')
* @param {TEventCallback} handler event listener to unsubscribe
*/
off<K extends keyof EventSpec>(eventName: K, handler: TEventCallback): void;
/**
* unsubscribe event listeners
* @param handlers handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
*/
off(handlers: EventRegistryObject): void;
/**
* unsubscribe all event listeners
*/
off(): void;
off<K extends keyof EventSpec>(

@@ -136,0 +142,0 @@ arg0?: K | EventRegistryObject,

@@ -17,28 +17,23 @@ //@ts-nocheck

}
let viewBoxAttr = element.getAttribute('viewBox'),
scaleX = 1,
scaleY = 1,
minX = 0,
minY = 0,
viewBoxWidth,
viewBoxHeight,
matrix,
el,
widthAttr = element.getAttribute('width'),
heightAttr = element.getAttribute('height'),
x = element.getAttribute('x') || 0,
y = element.getAttribute('y') || 0,
preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '',
missingViewBox =
!viewBoxAttr || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue)),
missingDimAttr =
!widthAttr ||
!heightAttr ||
widthAttr === '100%' ||
heightAttr === '100%',
toBeParsed = missingViewBox && missingDimAttr,
parsedDim = {},
translateMatrix = '',
widthDiff = 0,
heightDiff = 0;
let viewBoxAttr = element.getAttribute('viewBox');
let scaleX = 1;
let scaleY = 1;
let minX = 0;
let minY = 0;
let matrix;
let el;
const widthAttr = element.getAttribute('width');
const heightAttr = element.getAttribute('height');
const x = element.getAttribute('x') || 0;
const y = element.getAttribute('y') || 0;
let preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '';
const missingViewBox =
!viewBoxAttr || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue));
const missingDimAttr =
!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%';
const toBeParsed = missingViewBox && missingDimAttr;
const parsedDim = {};
let translateMatrix = '';
let widthDiff = 0;
let heightDiff = 0;

@@ -76,4 +71,4 @@ parsedDim.width = 0;

minY = -parseFloat(viewBoxAttr[2]);
viewBoxWidth = parseFloat(viewBoxAttr[3]);
viewBoxHeight = parseFloat(viewBoxAttr[4]);
const viewBoxWidth = parseFloat(viewBoxAttr[3]);
const viewBoxHeight = parseFloat(viewBoxAttr[4]);
parsedDim.minX = minX;

@@ -80,0 +75,0 @@ parsedDim.minY = minY;

@@ -18,7 +18,4 @@ //@ts-nocheck

export const commaWsp = '(?:\\s+,?\\s*|,\\s*)';
export const commaWsp = String.raw`(?:\s+,?\s*|,\s*|$)`;
export const rePathCommand =
/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/gi;
export const reFontDeclaration = new RegExp(

@@ -25,0 +22,0 @@ '(normal|italic)?\\s*(normal|small-caps)?\\s*' +

@@ -1,3 +0,1 @@

//@ts-nocheck
/**

@@ -7,3 +5,3 @@ * @private

*/
export function elementById(doc, id) {
export function elementById(doc: Document, id: string) {
let el;

@@ -14,6 +12,6 @@ doc.getElementById && (el = doc.getElementById(id));

}
let node,
i,
len,
nodelist = doc.getElementsByTagName('*');
let node;
let i;
let len;
const nodelist = doc.getElementsByTagName('*');
for (i = 0, len = nodelist.length; i < len; i++) {

@@ -20,0 +18,0 @@ node = nodelist[i];

@@ -1,3 +0,1 @@

//@ts-nocheck
import { selectorMatches } from './selectorMatches';

@@ -10,7 +8,6 @@ import { doesSomeParentMatch } from './doesSomeParentMatch';

export function elementMatchesRule(element, selectors) {
let firstMatching,
parentMatching = true;
//start from rightmost selector.
firstMatching = selectorMatches(element, selectors.pop());
export function elementMatchesRule(element: HTMLElement, selectors: string[]) {
let parentMatching = true;
// start from rightmost selector.
const firstMatching = selectorMatches(element, selectors.pop()!);
if (firstMatching && selectors.length) {

@@ -17,0 +14,0 @@ parentMatching = doesSomeParentMatch(element, selectors);

@@ -5,3 +5,3 @@ //@ts-nocheck

import { Image } from '../shapes/Image';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import {

@@ -120,3 +120,3 @@ invertTransform,

proto.resolveClipPath = function (obj, usingElement) {
var clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'),
let clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'),
element,

@@ -123,0 +123,0 @@ klass,

@@ -9,7 +9,7 @@ //@ts-nocheck

export function getCSSRules(doc) {
let styles = doc.getElementsByTagName('style'),
i,
len,
allRules = {},
rules;
const styles = doc.getElementsByTagName('style');
let i;
let len;
const allRules = {};
let rules;

@@ -16,0 +16,0 @@ // very crude parsing of style contents

@@ -19,7 +19,6 @@ //@ts-nocheck

export function getGradientDefs(doc) {
let elList = getMultipleNodes(doc, tagArray),
el,
j = 0,
gradientDefs = {};
j = elList.length;
const elList = getMultipleNodes(doc, tagArray);
let el;
const gradientDefs = {};
let j = elList.length;
while (j--) {

@@ -26,0 +25,0 @@ el = elList[j];

//@ts-nocheck
import { getEnv } from '../env';
import { getWindow } from '../env';
import { parseSVGDocument } from './parseSVGDocument';

@@ -16,3 +16,3 @@

export function loadSVGFromString(string, callback, reviver, options) {
const parser = new (getEnv().window.DOMParser)(),
const parser = new (getWindow().DOMParser)(),
doc = parser.parseFromString(string.trim(), 'text/xml');

@@ -19,0 +19,0 @@ parseSVGDocument(

@@ -7,4 +7,4 @@ //@ts-nocheck

export function normalizeValue(attr, value, parentAttributes, fontSize) {
let isArray = Array.isArray(value),
parsed;
const isArray = Array.isArray(value);
let parsed;

@@ -49,3 +49,3 @@ if ((attr === 'fill' || attr === 'stroke') && value === 'none') {

const strokeIndex = value.indexOf('stroke');
var value = 'fill';
value = 'fill';
if (fillIndex > -1 && strokeIndex > -1 && strokeIndex < fillIndex) {

@@ -52,0 +52,0 @@ value = 'stroke';

@@ -20,7 +20,5 @@ //@ts-nocheck

points = points.split(/\s+/);
let parsedPoints = [],
i,
len;
const parsedPoints = [];
for (i = 0, len = points.length; i < len; i += 2) {
for (let i = 0; i < points.length; i += 2) {
parsedPoints.push({

@@ -27,0 +25,0 @@ x: parseFloat(points[i]),

@@ -44,5 +44,3 @@ //@ts-nocheck

let svgUid = uid(),
i,
len,
const svgUid = uid(),
options = applyViewboxTransform(doc),

@@ -54,13 +52,2 @@ descendants = Array.from(doc.getElementsByTagName('*'));

if (descendants.length === 0 && isLikelyNode) {
// we're likely in node, where "o3-xml" library fails to gEBTN("*")
// https://github.com/ajaxorg/node-o3-xml/issues/21
descendants = doc.selectNodes('//*[name(.)!="svg"]');
const arr = [];
for (i = 0, len = descendants.length; i < len; i++) {
arr[i] = descendants[i];
}
descendants = arr;
}
const elements = descendants.filter(function (el) {

@@ -67,0 +54,0 @@ applyViewboxTransform(el);

@@ -101,4 +101,4 @@ //@ts-nocheck

// start with identity matrix
let matrix = iMatrix.concat(),
matrices = [];
let matrix = iMatrix.concat();
const matrices = [];

@@ -105,0 +105,0 @@ // return if no argument was given or

@@ -8,4 +8,4 @@ //@ts-nocheck

export function parseUseDirectives(doc) {
let nodelist = getMultipleNodes(doc, ['use', 'svg:use']),
i = 0;
const nodelist = getMultipleNodes(doc, ['use', 'svg:use']);
let i = 0;
while (nodelist.length && i < nodelist.length) {

@@ -19,20 +19,19 @@ const el = nodelist[i],

var xlink = xlinkAttribute.slice(1),
x = el.getAttribute('x') || 0,
y = el.getAttribute('y') || 0,
el2 = elementById(doc, xlink).cloneNode(true),
currentTrans =
(el2.getAttribute('transform') || '') +
' translate(' +
x +
', ' +
y +
')',
parentNode,
oldLength = nodelist.length,
attr,
j,
attrs,
len,
namespace = svgNS;
const xlink = xlinkAttribute.slice(1);
const x = el.getAttribute('x') || 0;
const y = el.getAttribute('y') || 0;
let el2 = elementById(doc, xlink).cloneNode(true);
let currentTrans =
(el2.getAttribute('transform') || '') +
' translate(' +
x +
', ' +
y +
')';
const oldLength = nodelist.length;
let attr;
let j;
let attrs;
let len;
const namespace = svgNS;

@@ -74,3 +73,3 @@ applyViewboxTransform(el2);

el2.removeAttribute('id');
parentNode = el.parentNode;
const parentNode = el.parentNode;
parentNode.replaceChild(el2, el);

@@ -77,0 +76,0 @@ // some browsers do not shorten nodelist after replaceChild (IE8)

@@ -1,9 +0,6 @@

//@ts-nocheck
export function selectorMatches(element, selector) {
let nodeName = element.nodeName,
classNames = element.getAttribute('class'),
id = element.getAttribute('id'),
matcher,
i;
export function selectorMatches(element: HTMLElement, selector: string) {
const nodeName = element.nodeName;
const classNames = element.getAttribute('class');
const id = element.getAttribute('id');
let matcher;
// i check if a selector matches slicing away part from it.

@@ -18,5 +15,8 @@ // if i get empty string i should match

if (classNames && selector.length) {
classNames = classNames.split(' ');
for (i = classNames.length; i--; ) {
matcher = new RegExp('\\.' + classNames[i] + '(?![a-zA-Z\\-]+)', 'i');
const splitClassNames = classNames.split(' ');
for (let i = splitClassNames.length; i--; ) {
matcher = new RegExp(
'\\.' + splitClassNames[i] + '(?![a-zA-Z\\-]+)',
'i'
);
selector = selector.replace(matcher, '');

@@ -23,0 +23,0 @@ }

@@ -20,8 +20,8 @@ //@ts-nocheck

}
const defaults = FabricObject.getDefaults();
if (typeof attributes[attr] === 'undefined') {
if (!FabricObject.prototype[attr]) {
if (!defaults[attr]) {
continue;
}
attributes[attr] = FabricObject.prototype[attr];
attributes[attr] = defaults[attr];
}

@@ -28,0 +28,0 @@

@@ -8,3 +8,3 @@ import { config } from './config';

import { toFixed } from './util/misc/toFixed';
import { classRegistry } from './util/class_registry';
import { classRegistry } from './ClassRegistry';

@@ -43,4 +43,18 @@ export type TPatternRepeat = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';

export class Pattern {
type = 'pattern';
/**
* Legacy identifier of the class. Prefer using this.constructor.name 'Pattern'
* or utils like isPattern
* Will be removed in fabric 7 or 8.
* @TODO add sustainable warning message
* @type string
* @deprecated
*/
get type() {
return 'pattern';
}
set type(value) {
console.warn('Setting type has no effect', value);
}
/**

@@ -213,2 +227,4 @@ * @type TPatternRepeat

classRegistry.setClass(Pattern);
// kept for compatibility reason
classRegistry.setClass(Pattern, 'pattern');

@@ -5,3 +5,3 @@ import { TMat2D, TRadian } from './typedefs';

export interface IPoint {
export interface XY {
x: number;

@@ -14,3 +14,3 @@ y: number;

*/
export class Point implements IPoint {
export class Point implements XY {
declare x: number;

@@ -22,4 +22,4 @@

constructor(x: number, y: number);
constructor(point: IPoint);
constructor(arg0: number | IPoint = 0, y = 0) {
constructor(point: XY);
constructor(arg0: number | XY = 0, y = 0) {
if (typeof arg0 === 'object') {

@@ -36,6 +36,6 @@ this.x = arg0.x;

* Adds another point to this one and returns another one
* @param {IPoint} that
* @param {XY} that
* @return {Point} new Point instance with added values
*/
add(that: IPoint): Point {
add(that: XY): Point {
return new Point(this.x + that.x, this.y + that.y);

@@ -46,3 +46,3 @@ }

* Adds another point to this one
* @param {IPoint} that
* @param {XY} that
* @return {Point} thisArg

@@ -52,3 +52,3 @@ * @chainable

*/
addEquals(that: IPoint): Point {
addEquals(that: XY): Point {
this.x += that.x;

@@ -83,6 +83,6 @@ this.y += that.y;

* Subtracts another point from this point and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point} new Point object with subtracted values
*/
subtract(that: IPoint): Point {
subtract(that: XY): Point {
return new Point(this.x - that.x, this.y - that.y);

@@ -93,3 +93,3 @@ }

* Subtracts another point from this point
* @param {IPoint} that
* @param {XY} that
* @return {Point} thisArg

@@ -99,3 +99,3 @@ * @chainable

*/
subtractEquals(that: IPoint): Point {
subtractEquals(that: XY): Point {
this.x -= that.x;

@@ -130,6 +130,6 @@ this.y -= that.y;

* Multiplies this point by another value and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
multiply(that: IPoint): Point {
multiply(that: XY): Point {
return new Point(this.x * that.x, this.y * that.y);

@@ -162,6 +162,6 @@ }

* Divides this point by another and returns a new one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
divide(that: IPoint): Point {
divide(that: XY): Point {
return new Point(this.x / that.x, this.y / that.y);

@@ -194,6 +194,6 @@ }

* Returns true if this point is equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
eq(that: IPoint): boolean {
eq(that: XY): boolean {
return this.x === that.x && this.y === that.y;

@@ -204,6 +204,6 @@ }

* Returns true if this point is less than another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
lt(that: IPoint): boolean {
lt(that: XY): boolean {
return this.x < that.x && this.y < that.y;

@@ -214,6 +214,6 @@ }

* Returns true if this point is less than or equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
lte(that: IPoint): boolean {
lte(that: XY): boolean {
return this.x <= that.x && this.y <= that.y;

@@ -225,6 +225,6 @@ }

* Returns true if this point is greater another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
gt(that: IPoint): boolean {
gt(that: XY): boolean {
return this.x > that.x && this.y > that.y;

@@ -235,6 +235,6 @@ }

* Returns true if this point is greater than or equal to another one
* @param {IPoint} that
* @param {XY} that
* @return {Boolean}
*/
gte(that: IPoint): boolean {
gte(that: XY): boolean {
return this.x >= that.x && this.y >= that.y;

@@ -245,7 +245,7 @@ }

* Returns new point which is the result of linear interpolation with this one and another one
* @param {IPoint} that
* @param {XY} that
* @param {Number} t , position of interpolation, between 0 and 1 default 0.5
* @return {Point}
*/
lerp(that: IPoint, t = 0.5): Point {
lerp(that: XY, t = 0.5): Point {
t = Math.max(Math.min(1, t), 0);

@@ -260,6 +260,6 @@ return new Point(

* Returns distance from this point and another one
* @param {IPoint} that
* @param {XY} that
* @return {Number}
*/
distanceFrom(that: IPoint): number {
distanceFrom(that: XY): number {
const dx = this.x - that.x,

@@ -272,6 +272,6 @@ dy = this.y - that.y;

* Returns the point between this point and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
midPointFrom(that: IPoint): Point {
midPointFrom(that: XY): Point {
return this.lerp(that);

@@ -282,6 +282,6 @@ }

* Returns a new point which is the min of this and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
min(that: IPoint): Point {
min(that: XY): Point {
return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));

@@ -292,6 +292,6 @@ }

* Returns a new point which is the max of this and another one
* @param {IPoint} that
* @param {XY} that
* @return {Point}
*/
max(that: IPoint): Point {
max(that: XY): Point {
return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));

@@ -342,6 +342,6 @@ }

* Sets x/y of this point from another point
* @param {IPoint} that
* @param {XY} that
* @chainable
*/
setFromPoint(that: IPoint) {
setFromPoint(that: XY) {
this.x = that.x;

@@ -354,5 +354,5 @@ this.y = that.y;

* Swaps x/y of this point and another point
* @param {IPoint} that
* @param {XY} that
*/
swap(that: IPoint) {
swap(that: XY) {
const x = this.x,

@@ -378,7 +378,7 @@ y = this.y;

* @memberOf fabric.util
* @param {IPoint} origin The origin of the rotation
* @param {XY} origin The origin of the rotation
* @param {TRadian} radians The radians of the angle for the rotation
* @return {Point} The new rotated point
*/
rotate(radians: TRadian, origin: IPoint = originZero): Point {
rotate(radians: TRadian, origin: XY = originZero): Point {
// TODO benchmark and verify the add and subtract how much cost

@@ -385,0 +385,0 @@ // and then in case early return if no origin is passed

@@ -7,2 +7,3 @@ import { Color } from './color/Color';

import { uid } from './util/internals/uid';
import { pickBy } from './util/misc/pick';
import { degreesToRadians } from './util/misc/radiansDegreesConversion';

@@ -12,2 +13,21 @@ import { toFixed } from './util/misc/toFixed';

export const shadowDefaultValues: Partial<TClassProperties<Shadow>> = {
color: 'rgb(0,0,0)',
blur: 0,
offsetX: 0,
offsetY: 0,
affectStroke: false,
includeDefaultValues: true,
nonScaling: false,
};
type TShadowSerializedProps = {
color: string;
blur: number;
offsetX: number;
offsetY: number;
affectStroke: boolean;
nonScaling: boolean;
};
export class Shadow {

@@ -66,2 +86,3 @@ /**

static ownDefaults = shadowDefaultValues;
/**

@@ -76,2 +97,3 @@ * @see {@link http://fabricjs.com/shadows|Shadow demo}

typeof arg0 === 'string' ? Shadow.parseShadow(arg0) : arg0;
Object.assign(this, (this.constructor as typeof Shadow).ownDefaults);
for (const prop in options) {

@@ -176,3 +198,3 @@ // @ts-expect-error for loops are so messy in TS

toObject() {
const data = {
const data: TShadowSerializedProps = {
color: this.color,

@@ -185,17 +207,6 @@ blur: this.blur,

};
if (this.includeDefaultValues) {
return data;
}
const defaults = Shadow.prototype;
const out: Record<string, unknown> = {};
for (const key in data) {
if (
data[key as keyof typeof data] !== defaults[key as keyof typeof data]
) {
out[key] = data[key as keyof typeof data];
}
}
return out;
const defaults = Shadow.ownDefaults;
return !this.includeDefaultValues
? pickBy(data, (value, key) => value !== defaults[key])
: data;
}

@@ -210,13 +221,1 @@

}
export const shadowDefaultValues: Partial<TClassProperties<Shadow>> = {
color: 'rgb(0,0,0)',
blur: 0,
offsetX: 0,
offsetY: 0,
affectStroke: false,
includeDefaultValues: true,
nonScaling: false,
};
Object.assign(Shadow.prototype, shadowDefaultValues);

@@ -1,4 +0,3 @@

import { ControlRenderingStyleOverride } from '../controls/controls.render';
import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import type { ControlRenderingStyleOverride } from '../controls/controlRendering';
import { classRegistry } from '../ClassRegistry';
import { Group } from './Group';

@@ -10,2 +9,12 @@ import type { FabricObject } from './Object/FabricObject';

/**
* controls how selected objects are added during a multiselection event
* - `canvas-stacking` adds the selected object to the active selection while respecting canvas object stacking order
* - `selection-order` adds the selected object to the top of the stack,
* meaning that the stack is ordered by the order in which objects were selected
* @default `canvas-stacking`
*/
multiSelectionStacking: 'canvas-stacking' | 'selection-order' =
'canvas-stacking';
constructor(

@@ -29,2 +38,32 @@ objects?: FabricObject[],

* @private
* @override we don't want the selection monitor to be active
*/
__objectSelectionMonitor() {
// noop
}
/**
* Adds objects with respect to {@link multiSelectionStacking}
* @param targets object to add to selection
*/
multiSelectAdd(...targets: FabricObject[]) {
if (this.multiSelectionStacking === 'selection-order') {
this.add(...targets);
} else {
// respect object stacking as it is on canvas
// perf enhancement for large ActiveSelection: consider a binary search of `isInFrontOf`
targets.forEach((target) => {
const index = this._objects.findIndex((obj) => obj.isInFrontOf(target));
const insertAt =
index === -1
? // `target` is in front of all other objects
this.size()
: index;
this.insertAt(insertAt, target);
});
}
}
/**
* @private
* @param {FabricObject} object

@@ -56,3 +95,3 @@ * @param {boolean} [removeParentTransform] true if object is in canvas coordinate plane

// return to owning group
parent.enterGroup(object);
parent._enterGroup(object, true);
delete object.__owningGroup;

@@ -152,10 +191,3 @@ }

export const activeSelectionDefaultValues: Partial<
TClassProperties<ActiveSelection>
> = {
type: 'activeSelection',
};
Object.assign(ActiveSelection.prototype, activeSelectionDefaultValues);
classRegistry.setClass(ActiveSelection);
classRegistry.setClass(ActiveSelection, 'activeSelection');

@@ -0,1 +1,2 @@

import type { ObjectEvents } from '../EventTypeDefs';
import { SHARED_ATTRIBUTES } from '../parser/attributes';

@@ -6,7 +7,12 @@ import { parseAttributes } from '../parser/parseAttributes';

import { sin } from '../util/misc/sin';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import { TClassProperties } from '../typedefs';
import {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
export class Circle extends FabricObject {
interface UniqueCircleProps {
/**

@@ -17,3 +23,3 @@ * Radius of this circle

*/
declare radius: number;
radius: number;

@@ -26,3 +32,3 @@ /**

*/
declare startAngle: number;
startAngle: number;

@@ -35,4 +41,42 @@ /**

*/
endAngle: number;
}
export interface SerializedCircleProps
extends SerializedObjectProps,
UniqueCircleProps {}
export interface CircleProps extends FabricObjectProps, UniqueCircleProps {}
const CIRCLE_PROPS = ['radius', 'startAngle', 'endAngle'] as const;
export const circleDefaultValues: UniqueCircleProps = {
radius: 0,
startAngle: 0,
endAngle: 360,
};
export class Circle<
Props extends TProps<CircleProps> = Partial<CircleProps>,
SProps extends SerializedCircleProps = SerializedCircleProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements UniqueCircleProps
{
declare radius: number;
declare startAngle: number;
declare endAngle: number;
static cacheProperties = [...cacheProperties, ...CIRCLE_PROPS];
static ownDefaults: Record<string, any> = circleDefaultValues;
static getDefaults(): Record<string, any> {
return {
...super.getDefaults(),
...Circle.ownDefaults,
};
}
/**

@@ -99,9 +143,7 @@ * @private

*/
toObject(propertiesToInclude: string[] = []): object {
return super.toObject([
'radius',
'startAngle',
'endAngle',
...propertiesToInclude,
]);
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return super.toObject([...CIRCLE_PROPS, ...propertiesToInclude]);
}

@@ -175,3 +217,3 @@

...otherParsedAttributes
} = parseAttributes(element, this.ATTRIBUTE_NAMES);
} = parseAttributes(element, this.ATTRIBUTE_NAMES) as Partial<CircleProps>;

@@ -196,17 +238,12 @@ if (!radius || radius < 0) {

/* _FROM_SVG_END_ */
/**
* @todo how do we declare this??
*/
static fromObject<T extends TProps<SerializedCircleProps>>(object: T) {
return super._fromObject<Circle>(object);
}
}
export const circleDefaultValues: Partial<TClassProperties<Circle>> = {
type: 'circle',
radius: 0,
startAngle: 0,
endAngle: 360,
};
Object.assign(Circle.prototype, {
...circleDefaultValues,
cacheProperties: [...cacheProperties, 'radius', 'startAngle', 'endAngle'],
});
classRegistry.setClass(Circle);
classRegistry.setSVGClass(Circle);

@@ -5,6 +5,37 @@ import { twoMathPi } from '../constants';

import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export class Ellipse extends FabricObject {
export const ellipseDefaultValues: UniqueEllipseProps = {
rx: 0,
ry: 0,
};
interface UniqueEllipseProps {
rx: number;
ry: number;
}
export interface SerializedEllipseProps
extends SerializedObjectProps,
UniqueEllipseProps {}
export interface EllipseProps extends FabricObjectProps, UniqueEllipseProps {}
const ELLIPSE_PROPS = ['rx', 'ry'] as const;
export class Ellipse<
Props extends TProps<EllipseProps> = Partial<EllipseProps>,
SProps extends SerializedEllipseProps = SerializedEllipseProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements EllipseProps
{
/**

@@ -24,9 +55,11 @@ * Horizontal radius

/**
* Constructor
* @param {Object} [options] Options object
* @return {Ellipse} thisArg
*/
constructor(options: Record<string, unknown>) {
super(options);
static cacheProperties = [...cacheProperties, ...ELLIPSE_PROPS];
static ownDefaults: Record<string, any> = ellipseDefaultValues;
static getDefaults() {
return {
...super.getDefaults(),
...Ellipse.ownDefaults,
};
}

@@ -77,4 +110,7 @@

*/
toObject(propertiesToInclude: string[] = []) {
return super.toObject(['rx', 'ry', ...propertiesToInclude]);
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return super.toObject([...ELLIPSE_PROPS, ...propertiesToInclude]);
}

@@ -145,14 +181,3 @@

export const ellipseDefaultValues: Partial<TClassProperties<Ellipse>> = {
type: 'ellipse',
rx: 0,
ry: 0,
};
Object.assign(Ellipse.prototype, {
...ellipseDefaultValues,
cacheProperties: [...cacheProperties, 'rx', 'ry'],
});
classRegistry.setClass(Ellipse);
classRegistry.setSVGClass(Ellipse);

@@ -6,4 +6,5 @@ // @ts-nocheck

import { Point } from '../Point';
import type { TClassProperties } from '../typedefs';
import { cos } from '../util/misc/cos';
import type { TClassProperties, TSVGReviver } from '../typedefs';
import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints';
import {

@@ -21,5 +22,10 @@ invertTransform,

import { sin } from '../util/misc/sin';
import { FabricObject, stateProperties } from './Object/FabricObject';
import { FabricObject } from './Object/FabricObject';
import { Rect } from './Rect';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';

@@ -82,2 +88,23 @@ export type LayoutContextType =

export interface GroupOwnProps {
layout: LayoutStrategy;
subTargetCheck: boolean;
interactive: boolean;
}
export interface SerializedGroupProps
extends SerializedObjectProps,
GroupOwnProps {
objects: SerializedObjectProps[];
}
export interface GroupProps extends FabricObjectProps, GroupOwnProps {}
export const groupDefaultValues = {
layout: 'fit-content',
strokeWidth: 0,
subTargetCheck: false,
interactive: false,
};
/**

@@ -88,3 +115,5 @@ * @fires object:added

*/
export class Group extends createCollectionMixin(FabricObject<GroupEvents>) {
export class Group extends createCollectionMixin(
FabricObject<GroupProps, SerializedGroupProps, GroupEvents>
) {
/**

@@ -94,3 +123,2 @@ * Specifies the **layout strategy** for instance

* `fit-content`, `fit-content-lazy`, `fixed`, `clip-path` are supported out of the box
* @type LayoutStrategy
* @default

@@ -125,2 +153,19 @@ */

static stateProperties: string[] = [
...FabricObject.stateProperties,
'layout',
];
static ownDefaults: Record<string, any> = groupDefaultValues;
private __objectSelectionTracker: (ev: ObjectEvents['selected']) => void;
private __objectSelectionDisposer: (ev: ObjectEvents['deselected']) => void;
private _firstLayoutDone = false;
static getDefaults(): Record<string, any> {
return {
...super.getDefaults(),
...Group.ownDefaults,
};
}
/**

@@ -135,3 +180,3 @@ * Constructor

objects: FabricObject[] = [],
options: any = {},
options: Partial<GroupProps> = {},
objectsRelativeToGroup?: boolean

@@ -150,3 +195,2 @@ ) {

);
this._firstLayoutDone = false;
// setting angle, skewX, skewY must occur after initial layout

@@ -323,4 +367,4 @@ this.set({ ...options, angle: 0, skewX: 0, skewY: 0 });

*/
__objectMonitor(opt) {
this._applyLayoutStrategy({ ...opt, type: 'object_modified' });
__objectMonitor(ev: ObjectEvents['modified']) {
this._applyLayoutStrategy({ ...ev, type: 'object_modified' });
this._set('dirty', true);

@@ -333,4 +377,6 @@ }

*/
__objectSelectionMonitor(selected: boolean, opt) {
const object = opt.target;
__objectSelectionMonitor<T extends boolean>(
selected: T,
{ target: object }: ObjectEvents[T extends true ? 'selected' : 'deselected']
) {
if (selected) {

@@ -496,3 +542,14 @@ this._activeObjects.push(object);

for (let i = 0; i < this._objects.length; i++) {
this._objects[i].render(ctx);
// TODO: handle rendering edge case somehow
if (
this.canvas?.preserveObjectStacking &&
this._objects[i].group !== this
) {
ctx.save();
ctx.transform(...invertTransform(this.calcTransformMatrix()));
this._objects[i].render(ctx);
ctx.restore();
} else if (this._objects[i].group === this) {
this._objects[i].render(ctx);
}
}

@@ -526,3 +583,5 @@ this._drawClipPath(ctx, this.clipPath);

*/
triggerLayout(context) {
triggerLayout<T extends this['layout']>(
context?: Partial<LayoutResult> & { layout?: T }
) {
if (context && context.layout) {

@@ -555,3 +614,3 @@ context.prevLayout = this.layout;

*/
_applyLayoutStrategy(context) {
_applyLayoutStrategy(context: LayoutContext) {
const isFirstLayout = context.type === 'initialization';

@@ -571,3 +630,3 @@ if (!isFirstLayout && !this._firstLayoutDone) {

this.layout,
this._objects.concat(),
[...this._objects],
context

@@ -588,3 +647,3 @@ );

this.forEachObject((object) => {
this._adjustObjectPosition(object, diff);
object.group === this && this._adjustObjectPosition(object, diff);
});

@@ -612,2 +671,3 @@ // clip path as well

initialTransform && this.set(initialTransform);
diff = new Point();
} else {

@@ -647,4 +707,4 @@ // no `result` so we return

*/
getLayoutStrategyResult(
layoutDirective: LayoutStrategy,
getLayoutStrategyResult<T extends this['layout']>(
layoutDirective: T,
objects: FabricObject[],

@@ -722,8 +782,2 @@ context: LayoutContext

}
} else if (layoutDirective === 'svg' && context.type === 'initialization') {
const bbox = this.getObjectsBoundingBox(objects, true) || {};
return Object.assign(bbox, {
correctionX: -bbox.offsetX || 0,
correctionY: -bbox.offsetY || 0,
});
}

@@ -741,4 +795,4 @@ }

*/
prepareBoundingBox(
layoutDirective: LayoutStrategy,
prepareBoundingBox<T extends this['layout']>(
layoutDirective: T,
objects: FabricObject[],

@@ -750,6 +804,6 @@ context: LayoutContext

} else if (context.type === 'imperative' && context.context) {
return Object.assign(
this.getObjectsBoundingBox(objects) || {},
context.context
);
return {
...(this.getObjectsBoundingBox(objects) || {}),
...context.context,
};
} else {

@@ -768,4 +822,4 @@ return this.getObjectsBoundingBox(objects);

*/
prepareInitialBoundingBox(
layoutDirective: LayoutStrategy,
prepareInitialBoundingBox<T extends this['layout']>(
layoutDirective: T,
objects: FabricObject[],

@@ -794,6 +848,7 @@ context: LayoutContext

const bbox = this.getObjectsBoundingBox(objects) || {};
const width = hasWidth ? this.width : bbox.width || 0,
height = hasHeight ? this.height : bbox.height || 0,
calculatedCenter = new Point(bbox.centerX || 0, bbox.centerY || 0),
const bbox = this.getObjectsBoundingBox(objects) || ({} as LayoutResult);
const { centerX = 0, centerY = 0, width: w = 0, height: h = 0 } = bbox;
const width = hasWidth ? this.width : w,
height = hasHeight ? this.height : h,
calculatedCenter = new Point(centerX, centerY),
origin = new Point(

@@ -877,4 +932,4 @@ resolveOrigin(this.originX),

}
let min: Point, max: Point;
objects.forEach((object, i) => {
const objectBounds: Point[] = [];
objects.forEach((object) => {
const objCenter = object.getRelativeCenterPoint();

@@ -890,24 +945,18 @@ let sizeVector = object._getTransformedDimensions().scalarDivide(2);

}
const a = objCenter.subtract(sizeVector);
const b = objCenter.add(sizeVector);
if (i === 0) {
min = new Point(Math.min(a.x, b.x), Math.min(a.y, b.y));
max = new Point(Math.max(a.x, b.x), Math.max(a.y, b.y));
} else {
min.setXY(Math.min(min.x, a.x, b.x), Math.min(min.y, a.y, b.y));
max.setXY(Math.max(max.x, a.x, b.x), Math.max(max.y, a.y, b.y));
}
objectBounds.push(
objCenter.subtract(sizeVector),
objCenter.add(sizeVector)
);
});
const { left, top, width, height } =
makeBoundingBoxFromPoints(objectBounds);
const size = max.subtract(min),
relativeCenter = ignoreOffset
? size.scalarDivide(2)
: min.midPointFrom(max),
const size = new Point(width, height),
relativeCenter = (!ignoreOffset ? new Point(left, top) : new Point()).add(
size.scalarDivide(2)
),
// we send `relativeCenter` up to group's containing plane
offset = min.transform(this.calcOwnMatrix()),
center = relativeCenter.transform(this.calcOwnMatrix());
return {
offsetX: offset.x,
offsetY: offset.y,
centerX: center.x,

@@ -962,11 +1011,18 @@ centerY: center.y,

*/
toObject(propertiesToInclude: (keyof this)[] = []) {
const obj = super.toObject([
'layout',
'subTargetCheck',
'interactive',
...propertiesToInclude,
]);
obj.objects = this.__serializeObjects('toObject', propertiesToInclude);
return obj;
toObject<
T extends Omit<
GroupProps & TClassProperties<this>,
keyof SerializedGroupProps
>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SerializedGroupProps {
return {
...super.toObject([
'layout',
'subTargetCheck',
'interactive',
...propertiesToInclude,
]),
objects: this.__serializeObjects('toObject', propertiesToInclude),
};
}

@@ -990,10 +1046,11 @@

*/
_createSVGBgRect(reviver?: (markup: string) => any) {
_createSVGBgRect(reviver?: TSVGReviver) {
if (!this.backgroundColor) {
return '';
}
const fillStroke = Rect.prototype._toSVG.call(this, reviver);
const fillStroke = Rect.prototype._toSVG.call(this);
const commons = fillStroke.indexOf('COMMON_PARTS');
fillStroke[commons] = 'for="group" ';
return fillStroke.join('');
const markup = fillStroke.join('');
return reviver ? reviver(markup) : markup;
}

@@ -1003,6 +1060,6 @@

* Returns svg representation of an instance
* @param {Function} [reviver] Method for further parsing of svg representation.
* @param {TSVGReviver} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
_toSVG(reviver?: (markup: string) => any) {
_toSVG(reviver?: TSVGReviver) {
const svgString = ['<g ', 'COMMON_PARTS', ' >\n'];

@@ -1036,3 +1093,3 @@ const bg = this._createSVGBgRect(reviver);

*/
toClipPathSVG(reviver?: (markup: string) => any) {
toClipPathSVG(reviver?: TSVGReviver) {
const svgString = [];

@@ -1057,3 +1114,6 @@ const bg = this._createSVGBgRect(reviver);

*/
static fromObject({ objects = [], ...options }) {
static fromObject<T extends TProps<SerializedGroupProps>>({
objects = [],
...options
}: T) {
return Promise.all([

@@ -1069,15 +1129,2 @@ enlivenObjects(objects),

export const groupDefaultValues: Partial<TClassProperties<Group>> = {
type: 'group',
layout: 'fit-content',
strokeWidth: 0,
subTargetCheck: false,
interactive: false,
};
Object.assign(Group.prototype, {
...groupDefaultValues,
stateProperties: [...stateProperties, 'layout'],
});
classRegistry.setClass(Group);

@@ -1,3 +0,3 @@

//@ts-nocheck
import { getEnv } from '../env';
// @ts-nocheck
import { getDocument, getEnv } from '../env';
import type { BaseFilter } from '../filters/BaseFilter';

@@ -8,3 +8,2 @@ import { getFilterBackend } from '../filters/FilterBackend';

import { TClassProperties, TSize } from '../typedefs';
import { cleanUpJsdomNode } from '../util/dom_misc';
import { uid } from '../util/internals/uid';

@@ -20,5 +19,14 @@ import { createCanvasElement } from '../util/misc/dom';

import { parsePreserveAspectRatioAttribute } from '../util/misc/svgParsing';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
import { WebGLFilterBackend } from '../filters/WebGLFilterBackend';
// @todo Would be nice to have filtering code not imported directly.
export type ImageSource =

@@ -29,6 +37,47 @@ | HTMLImageElement

interface UniqueImageProps {
srcFromAttribute: boolean;
minimumScaleTrigger: number;
cropX: number;
cropY: number;
imageSmoothing: boolean;
crossOrigin: string | null;
filters: BaseFilter[];
resizeFilter?: BaseFilter;
}
export const imageDefaultValues: Partial<UniqueImageProps> &
Partial<FabricObjectProps> = {
strokeWidth: 0,
srcFromAttribute: false,
minimumScaleTrigger: 0.5,
cropX: 0,
cropY: 0,
imageSmoothing: true,
};
export interface SerializedImageProps extends SerializedObjectProps {
src: string;
crossOrigin: string | null;
filters: any[];
resizeFilter?: any;
cropX: number;
cropY: number;
}
export interface ImageProps extends FabricObjectProps, UniqueImageProps {}
const IMAGE_PROPS = ['cropX', 'cropY'] as const;
/**
* @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}
*/
export class Image extends FabricObject {
export class Image<
Props extends TProps<ImageProps> = Partial<ImageProps>,
SProps extends SerializedImageProps = SerializedImageProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements ImageProps
{
/**

@@ -125,2 +174,12 @@ * When calling {@link Image.getSrc}, return value from element src with `element.getAttribute('src')`.

static cacheProperties = [...cacheProperties, ...IMAGE_PROPS];
static ownDefaults: Record<string, any> = imageDefaultValues;
static getDefaults() {
return {
...super.getDefaults(),
...Image.ownDefaults,
};
}
/**

@@ -135,10 +194,11 @@ * Constructor

*/
constructor(elementId: string, options: any = {});
constructor(element: ImageSource, options: any = {});
constructor(arg0: ImageSource | string, options: any = {}) {
constructor(elementId: string, options: Props);
constructor(element: ImageSource, options: Props);
constructor(arg0: ImageSource | string, options: Props = {} as Props) {
super({ filters: [], ...options });
this.cacheKey = `texture${uid()}`;
this.setElement(
(typeof arg0 === 'string' && getEnv().document.getElementById(arg0)) ||
arg0,
typeof arg0 === 'string'
? (getDocument().getElementById(arg0) as ImageSource)
: arg0,
options

@@ -186,3 +246,3 @@ );

const backend = getFilterBackend(false);
if (backend && backend.evictCachesForKey) {
if (backend instanceof WebGLFilterBackend) {
backend.evictCachesForKey(key);

@@ -201,6 +261,6 @@ }

['_originalElement', '_element', '_filteredEl', '_cacheCanvas'].forEach(
(element) => {
cleanUpJsdomNode(this[element as keyof this]);
(elementKey) => {
getEnv().dispose(this[elementKey as keyof this] as Element);
// @ts-expect-error disposing
this[element] = undefined;
this[elementKey] = undefined;
}

@@ -213,3 +273,3 @@ );

*/
getCrossOrigin() {
getCrossOrigin(): string | null {
return (

@@ -262,3 +322,6 @@ this._originalElement &&

*/
toObject(propertiesToInclude: (keyof this)[] = []): Record<string, any> {
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
const filters: Record<string, any>[] = [];

@@ -269,3 +332,3 @@ this.filters.forEach((filterObj) => {

return {
...super.toObject(['cropX', 'cropY', ...propertiesToInclude]),
...super.toObject([...IMAGE_PROPS, ...propertiesToInclude]),
src: this.getSrc(),

@@ -345,3 +408,3 @@ crossOrigin: this.getCrossOrigin(),

'" height="',
element.height || element.height,
element.height || element.naturalHeight,
imageRendering,

@@ -385,3 +448,3 @@ '"',

*/
getSrc(filtered?: boolean) {
getSrc(filtered?: boolean): string {
const element = filtered ? this._element : this._originalElement;

@@ -732,9 +795,10 @@ if (element) {

*/
static fromObject(
{ filters: f, resizeFilter: rf, src, crossOrigin, ...object }: any,
static fromObject<T extends TProps<SerializedImageProps>>(
{ filters: f, resizeFilter: rf, src, crossOrigin, ...object }: T,
options: { signal: AbortSignal }
): Promise<Image> {
) {
return Promise.all([
loadImage(src, { ...options, crossOrigin }),
f && enlivenObjects(f, options),
// TODO: redundant - handled by enlivenObjectEnlivables
rf && enlivenObjects([rf], options),

@@ -761,3 +825,6 @@ enlivenObjectEnlivables(object, options),

*/
static fromURL(url: string, options: LoadImageOptions = {}): Promise<Image> {
static fromURL<T extends TProps<SerializedImageProps>>(
url: string,
options: T & LoadImageOptions = {}
): Promise<Image> {
return loadImage(url, options).then((img) => new this(img, options));

@@ -787,18 +854,3 @@ }

export const imageDefaultValues: Partial<TClassProperties<Image>> = {
type: 'image',
strokeWidth: 0,
srcFromAttribute: false,
minimumScaleTrigger: 0.5,
cropX: 0,
cropY: 0,
imageSmoothing: true,
};
Object.assign(Image.prototype, {
...imageDefaultValues,
cacheProperties: [...cacheProperties, 'cropX', 'cropY'],
});
classRegistry.setClass(Image);
classRegistry.setSVGClass(Image);
import type { Canvas } from '../../canvas/Canvas';
import { getEnv } from '../../env';
import { getDocument } from '../../env';
import {

@@ -12,4 +12,2 @@ DragEventData,

import { cloneDeep } from '../../util/internals/cloneDeep';
import { createCanvasElement } from '../../util/misc/dom';
import { isIdentityMatrix } from '../../util/misc/matrix';
import { TextStyleDeclaration } from '../Text/StyledText';

@@ -144,4 +142,6 @@

target.setSelectionStyles(styleOverride, selectionEnd, target.text.length);
let dragImage = target.toCanvasElement({
target.dirty = true;
const dragImage = target.toCanvasElement({
enableRetinaScaling,
viewportTransform: true,
});

@@ -151,17 +151,11 @@ // restore values

target.styles = styles;
// handle retina scaling and vpt
if (retinaScaling > 1 || !isIdentityMatrix(vpt)) {
const dragImageCanvas = createCanvasElement();
const size = new Point(dragImage.width, dragImage.height)
.scalarDivide(retinaScaling)
.transform(vpt, true);
dragImageCanvas.width = size.x;
dragImageCanvas.height = size.y;
const ctx = dragImageCanvas.getContext('2d')!;
ctx.scale(1 / retinaScaling, 1 / retinaScaling);
const [a, b, c, d] = vpt;
ctx.transform(a, b, c, d, 0, 0);
ctx.drawImage(dragImage, 0, 0);
dragImage = dragImageCanvas;
}
target.dirty = true;
// position drag image offscreen
setStyle(dragImage, {
position: 'fixed',
left: `${-dragImage.width}px`,
border: 'none',
width: `${dragImage.width / retinaScaling}px`,
height: `${dragImage.height / retinaScaling}px`,
});
this.__dragImageDisposer && this.__dragImageDisposer();

@@ -171,9 +165,3 @@ this.__dragImageDisposer = () => {

};
// position drag image offscreen
setStyle(dragImage, {
position: 'absolute',
left: -dragImage.width + 'px',
border: 'none',
});
getEnv().document.body.appendChild(dragImage);
getDocument().body.appendChild(dragImage);
e.dataTransfer?.setDragImage(dragImage, offset.x, offset.y);

@@ -308,3 +296,3 @@ }

}
target.insertChars('', undefined, selectionStart, selectionEnd);
target.removeChars(selectionStart, selectionEnd);
// prevent `dragend` from handling event

@@ -373,3 +361,3 @@ delete this.__dragStartSelection;

if (dropEffect === 'move') {
target.insertChars('', undefined, selectionStart, selectionEnd);
target.removeChars(selectionStart, selectionEnd);
target.selectionStart = target.selectionEnd = selectionStart;

@@ -376,0 +364,0 @@ target.hiddenTextarea &&

@@ -11,3 +11,4 @@ import { Canvas } from '../../canvas/Canvas';

import { AssertKeys, TFiller } from '../../typedefs';
import { classRegistry } from '../../util/class_registry';
import { classRegistry } from '../../ClassRegistry';
import type { SerializedTextProps, TextProps } from '../Text/Text';

@@ -21,2 +22,36 @@ type CursorBoundaries = {

export const iTextDefaultValues = {
selectionStart: 0,
selectionEnd: 0,
selectionColor: 'rgba(17,119,255,0.3)',
isEditing: false,
editable: true,
editingBorderColor: 'rgba(102,153,255,0.25)',
cursorWidth: 2,
cursorColor: '',
cursorDelay: 1000,
cursorDuration: 600,
caching: true,
hiddenTextareaContainer: null,
_selectionDirection: null,
_reSpace: /\s|\n/,
inCompositionMode: false,
keysMap,
keysMapRtl,
ctrlKeysMapDown,
ctrlKeysMapUp,
};
// @TODO this is not complete
interface UniqueITextProps {
selectionStart: number;
selectionEnd: number;
}
export interface SerializedITextProps
extends SerializedTextProps,
UniqueITextProps {}
export interface ITextProps extends TextProps, UniqueITextProps {}
/**

@@ -66,4 +101,9 @@ * @fires changed

export class IText<
EventSpec extends ITextEvents = ITextEvents
> extends ITextClickBehavior<EventSpec> {
Props extends ITextProps = ITextProps,
SProps extends SerializedITextProps = SerializedITextProps,
EventSpec extends ITextEvents = ITextEvents
>
extends ITextClickBehavior<Props, SProps, EventSpec>
implements UniqueITextProps
{
/**

@@ -155,2 +195,12 @@ * Index where text selection starts (or where cursor is when there is no selection)

static ownDefaults: Record<string, any> = iTextDefaultValues;
static getDefaults() {
return { ...super.getDefaults(), ...IText.ownDefaults };
}
get type() {
return 'i-text';
}
/**

@@ -645,27 +695,4 @@

export const iTextDefaultValues = {
type: 'i-text',
selectionStart: 0,
selectionEnd: 0,
selectionColor: 'rgba(17,119,255,0.3)',
isEditing: false,
editable: true,
editingBorderColor: 'rgba(102,153,255,0.25)',
cursorWidth: 2,
cursorColor: '',
cursorDelay: 1000,
cursorDuration: 600,
caching: true,
hiddenTextareaContainer: null,
_selectionDirection: null,
_reSpace: /\s|\n/,
inCompositionMode: false,
keysMap,
keysMapRtl,
ctrlKeysMapDown,
ctrlKeysMapUp,
};
Object.assign(IText.prototype, iTextDefaultValues);
classRegistry.setClass(IText);
// legacy
classRegistry.setClass(IText, 'i-text');

@@ -1,2 +0,2 @@

import { getEnv } from '../../env';
import { getDocument } from '../../env';
import {

@@ -13,5 +13,19 @@ ObjectEvents,

import type { ValueAnimation } from '../../util/animation/ValueAnimation';
import { TextStyleDeclaration } from '../Text/StyledText';
import type { TextStyleDeclaration } from '../Text/StyledText';
import type { SerializedTextProps, TextProps } from '../Text/Text';
import { TProps } from '../Object/types';
// extend this regex to support non english languages
/**
* extend this regex to support non english languages
*
* - ` ` Matches a SPACE character (char code 32).
* - `\n` Matches a LINE FEED character (char code 10).
* - `\.` Matches a "." character (char code 46).
* - `,` Matches a "," character (char code 44).
* - `;` Matches a ";" character (char code 59).
* - `!` Matches a "!" character (char code 33).
* - `\?` Matches a "?" character (char code 63).
* - `\-` Matches a "-" character (char code 45).
*/
// eslint-disable-next-line no-useless-escape
const reNonWord = /[ \n\.,;!\?\-]/;

@@ -28,4 +42,6 @@

export abstract class ITextBehavior<
Props extends TProps<TextProps> = Partial<TextProps>,
SProps extends SerializedTextProps = SerializedTextProps,
EventSpec extends ITextEvents = ITextEvents
> extends Text<EventSpec> {
> extends Text<Props, SProps, EventSpec> {
declare abstract isEditing: boolean;

@@ -393,3 +409,3 @@ declare abstract cursorDelay: number;

// regain focus
getEnv().document.activeElement !== this.hiddenTextarea &&
getDocument().activeElement !== this.hiddenTextarea &&
this.hiddenTextarea!.focus();

@@ -505,11 +521,11 @@

this.cursorOffsetCache = {};
this.text = this.hiddenTextarea.value;
if (this._shouldClearDimensionCache()) {
this.initDimensions();
this.setCoords();
}
const textarea = this.hiddenTextarea;
this.text = textarea.value;
this.set('dirty', true);
this.initDimensions();
this.setCoords();
const newSelection = this.fromStringToGraphemeSelection(
this.hiddenTextarea.selectionStart,
this.hiddenTextarea.selectionEnd,
this.hiddenTextarea.value
textarea.selectionStart,
textarea.selectionEnd,
textarea.value
);

@@ -664,3 +680,3 @@ this.selectionEnd = this.selectionStart = newSelection.selectionEnd;

this._restoreEditingProps();
if (this._shouldClearDimensionCache()) {
if (this._forceClearCache) {
this.initDimensions();

@@ -974,6 +990,3 @@ this.setCoords();

*/
removeChars(start: number, end: number) {
if (typeof end === 'undefined') {
end = start + 1;
}
removeChars(start: number, end: number = start + 1) {
this.removeStyleFromTo(start, end);

@@ -983,6 +996,4 @@ this._text.splice(start, end - start);

this.set('dirty', true);
if (this._shouldClearDimensionCache()) {
this.initDimensions();
this.setCoords();
}
this.initDimensions();
this.setCoords();
this._removeExtraneousStyles();

@@ -1021,6 +1032,4 @@ }

this.set('dirty', true);
if (this._shouldClearDimensionCache()) {
this.initDimensions();
this.setCoords();
}
this.initDimensions();
this.setCoords();
this._removeExtraneousStyles();

@@ -1027,0 +1036,0 @@ }

import type { TPointerEvent, TPointerEventInfo } from '../../EventTypeDefs';
import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import type { DragMethods } from '../Object/InteractiveObject';

@@ -9,2 +9,4 @@ import { stopEvent } from '../../util/dom_event';

import { ITextKeyBehavior } from './ITextKeyBehavior';
import { TProps } from '../Object/types';
import { TextProps, SerializedTextProps } from '../Text/Text';

@@ -19,5 +21,7 @@ // TODO: this code seems wrong.

export abstract class ITextClickBehavior<
Props extends TProps<TextProps> = Partial<TextProps>,
SProps extends SerializedTextProps = SerializedTextProps,
EventSpec extends ITextEvents = ITextEvents
>
extends ITextKeyBehavior<EventSpec>
extends ITextKeyBehavior<Props, SProps, EventSpec>
implements DragMethods

@@ -28,3 +32,3 @@ {

private declare __lastLastClickTime: number;
private declare __lastPointer: IPoint | Record<string, never>;
private declare __lastPointer: XY | Record<string, never>;
private declare __newClickTime: number;

@@ -94,3 +98,3 @@

isTripleClick(newPointer: IPoint) {
isTripleClick(newPointer: XY) {
return (

@@ -300,3 +304,3 @@ this.__newClickTime - this.__lastClickTime < 500 &&

_getNewSelectionStartFromOffset(
mouseOffset: IPoint,
mouseOffset: XY,
prevWidth: number,

@@ -303,0 +307,0 @@ width: number,

//@ts-nocheck
import { config } from '../../config';
import { getEnv } from '../../env';
import { getDocument, getEnv } from '../../env';
import { TPointerEvent } from '../../EventTypeDefs';

@@ -9,6 +9,10 @@ import { capValue } from '../../util/misc/capValue';

import type { TKeyMapIText } from './constants';
import { TProps } from '../Object/types';
import { TextProps, SerializedTextProps } from '../Text/Text';
export abstract class ITextKeyBehavior<
Props extends TProps<TextProps> = Partial<TextProps>,
SProps extends SerializedTextProps = SerializedTextProps,
EventSpec extends ITextEvents = ITextEvents
> extends ITextBehavior<EventSpec> {
> extends ITextBehavior<Props, SProps, EventSpec> {
/**

@@ -59,3 +63,3 @@ * For functionalities on keyDown

initHiddenTextarea() {
this.hiddenTextarea = getEnv().document.createElement('textarea');
this.hiddenTextarea = getDocument().createElement('textarea');
this.hiddenTextarea.setAttribute('autocapitalize', 'off');

@@ -75,3 +79,3 @@ this.hiddenTextarea.setAttribute('autocorrect', 'off');

} else {
getEnv().document.body.appendChild(this.hiddenTextarea);
getDocument().body.appendChild(this.hiddenTextarea);
}

@@ -180,2 +184,15 @@

}
const updateAndFire = () => {
this.updateFromTextArea();
this.fire('changed');
if (this.canvas) {
this.canvas.fire('text:changed', { target: this });
this.canvas.requestRenderAll();
}
};
if (this.hiddenTextarea.value === '') {
this.styles = {};
updateAndFire();
return;
}
// decisions about style changes.

@@ -195,12 +212,2 @@ const nextText = this._splitTextIntoLines(

removeTo;
if (this.hiddenTextarea.value === '') {
this.styles = {};
this.updateFromTextArea();
this.fire('changed');
if (this.canvas) {
this.canvas.fire('text:changed', { target: this });
this.canvas.requestRenderAll();
}
return;
}

@@ -273,8 +280,3 @@ const textareaSelection = this.fromStringToGraphemeSelection(

}
this.updateFromTextArea();
this.fire('changed');
if (this.canvas) {
this.canvas.fire('text:changed', { target: this });
this.canvas.requestRenderAll();
}
updateAndFire();
}

@@ -281,0 +283,0 @@

import { SHARED_ATTRIBUTES } from '../parser/attributes';
import { parseAttributes } from '../parser/parseAttributes';
import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import { Point } from '../Point';
import { isFiller } from '../util/types';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
// @TODO this code is terrible and Line should be a special case of polyline.
const coordProps = ['x1', 'x2', 'y1', 'y2'];
const coordProps = ['x1', 'x2', 'y1', 'y2'] as const;
export class Line extends FabricObject {
interface UniqueLineProps {
x1: number;
x2: number;
y1: number;
y2: number;
}
export interface SerializedLineProps
extends SerializedObjectProps,
UniqueLineProps {}
export class Line<
Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>,
SProps extends SerializedLineProps = SerializedLineProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements UniqueLineProps
{
/**
* x value or first line edge
* @type Number
* @type number
* @default

@@ -23,3 +47,3 @@ */

* y value or first line edge
* @type Number
* @type number
* @default

@@ -31,3 +55,3 @@ */

* x value or second line edge
* @type Number
* @type number
* @default

@@ -39,3 +63,3 @@ */

* y value or second line edge
* @type Number
* @type number
* @default

@@ -45,2 +69,3 @@ */

static cacheProperties = [...cacheProperties, ...coordProps];
/**

@@ -52,13 +77,8 @@ * Constructor

*/
constructor(
points = [0, 0, 0, 0],
options: Partial<TClassProperties<Line>> = {}
) {
constructor(points = [0, 0, 0, 0], options: Props = {} as Props) {
super(options);
this.set('x1', points[0]);
this.set('y1', points[1]);
this.set('x2', points[2]);
this.set('y2', points[3]);
this.x1 = points[0];
this.y1 = points[1];
this.x2 = points[2];
this.y2 = points[3];
this._setWidthHeight(options);

@@ -71,3 +91,3 @@ }

*/
_setWidthHeight({ left, top }: Partial<TClassProperties<Line>> = {}) {
_setWidthHeight({ left, top }: Partial<Props> = {}) {
this.width = Math.abs(this.x2 - this.x1);

@@ -86,3 +106,3 @@ this.height = Math.abs(this.y2 - this.y1);

super._set(key, value);
if (coordProps.includes(key)) {
if (coordProps.includes(key as keyof UniqueLineProps)) {
this._setWidthHeight();

@@ -135,4 +155,10 @@ }

*/
toObject(propertiesToInclude: string[]) {
return { ...super.toObject(propertiesToInclude), ...this.calcLinePoints() };
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return {
...super.toObject(propertiesToInclude),
...this.calcLinePoints(),
};
}

@@ -161,3 +187,3 @@

*/
calcLinePoints(): Record<string, number> {
calcLinePoints(): UniqueLineProps {
const xMult = this.x1 <= this.x2 ? -1 : 1,

@@ -279,3 +305,3 @@ yMult = this.y1 <= this.y2 ? -1 : 1,

*/
static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));
static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(coordProps);

@@ -310,4 +336,10 @@ /**

*/
static fromObject({ x1, y1, x2, y2, ...object }: Record<string, any>) {
return this._fromObject(
static fromObject<T extends TProps<SerializedLineProps>>({
x1,
y1,
x2,
y2,
...object
}: T) {
return this._fromObject<Line>(
{

@@ -320,22 +352,7 @@ ...object,

}
).then((fabricLine) => {
return fabricLine;
});
);
}
}
export const lineDefaultValues: Partial<TClassProperties<Line>> = {
type: 'line',
x1: 0,
y1: 0,
x2: 0,
y2: 0,
};
Object.assign(Line.prototype, {
...lineDefaultValues,
cacheProperties: [...cacheProperties, 'x1', 'x2', 'y1', 'y2'],
});
classRegistry.setClass(Line);
classRegistry.setSVGClass(Line);

@@ -1,3 +0,1 @@

import { getEnv } from '../../env';
export const stateProperties = [

@@ -39,3 +37,2 @@ 'top',

export const fabricObjectDefaultValues = {
type: 'object',
originX: 'left',

@@ -101,4 +98,3 @@ originY: 'top',

excludeFromExport: false,
// TODO: restore once default values are refactored to a method
objectCaching: true, // !getEnv().isLikelyNode
objectCaching: true,
noScaleCache: true,

@@ -114,2 +110,2 @@ strokeUniform: false,

FX_DURATION: 500,
};
} as const;

@@ -5,3 +5,5 @@ import { ObjectEvents } from '../../EventTypeDefs';

import { applyMixins } from '../../util/applyMixins';
import { StatefulMixin } from '../../mixins/stateful.mixin';
import { FabricObjectProps } from './types/FabricObjectProps';
import { TFabricObjectProps, SerializedObjectProps } from './types';
import { classRegistry } from '../../ClassRegistry';

@@ -11,11 +13,19 @@ // TODO somehow we have to make a tree-shakeable import

// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars
export interface FabricObject<EventSpec extends ObjectEvents = ObjectEvents>
extends FabricObjectSVGExportMixin {}
export interface FabricObject<
Props extends TFabricObjectProps = Partial<FabricObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
> extends FabricObjectSVGExportMixin {}
export class FabricObject<
Props extends TFabricObjectProps = Partial<FabricObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
> extends InteractiveFabricObject<EventSpec> {}
> extends InteractiveFabricObject<Props, SProps, EventSpec> {}
applyMixins(FabricObject, [FabricObjectSVGExportMixin, StatefulMixin]);
applyMixins(FabricObject, [FabricObjectSVGExportMixin]);
export { cacheProperties, stateProperties } from './defaultValues';
classRegistry.setClass(FabricObject);
classRegistry.setClass(FabricObject, 'object');
export { cacheProperties } from './defaultValues';

@@ -15,3 +15,6 @@ import { Point } from '../../Point';

import type { Canvas } from '../../canvas/Canvas';
import type { ControlRenderingStyleOverride } from '../../controls/controls.render';
import type { ControlRenderingStyleOverride } from '../../controls/controlRendering';
import { FabricObjectProps } from './types/FabricObjectProps';
import { TFabricObjectProps, SerializedObjectProps } from './types';
import { createObjectDefaultControls } from '../../controls/commonControls';

@@ -26,3 +29,3 @@ type TOCoord = Point & {

type TBorderRenderingStyleOverride = Partial<
Pick<FabricObject, 'borderColor' | 'borderDashArray'>
Pick<InteractiveFabricObject, 'borderColor' | 'borderDashArray'>
>;

@@ -33,3 +36,3 @@

Partial<
Pick<FabricObject, 'hasBorders' | 'hasControls'> & {
Pick<InteractiveFabricObject, 'hasBorders' | 'hasControls'> & {
forActiveSelection: boolean;

@@ -46,5 +49,51 @@ }

const interactiveDefaults = {};
export class InteractiveFabricObject<
EventSpec extends ObjectEvents = ObjectEvents
> extends FabricObject<EventSpec> {
Props extends TFabricObjectProps = Partial<FabricObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements FabricObjectProps
{
declare noScaleCache: boolean;
declare centeredScaling: false;
declare snapAngle?: TDegree;
declare snapThreshold?: TDegree;
declare lockMovementX: boolean;
declare lockMovementY: boolean;
declare lockRotation: boolean;
declare lockScalingX: boolean;
declare lockScalingY: boolean;
declare lockSkewingX: boolean;
declare lockSkewingY: boolean;
declare lockScalingFlip: boolean;
declare cornerSize: number;
declare touchCornerSize: number;
declare transparentCorners: boolean;
declare cornerColor: string;
declare cornerStrokeColor: string;
declare cornerStyle: 'rect' | 'circle';
declare cornerDashArray: number[] | null;
declare hasControls: boolean;
declare borderColor: string;
declare borderDashArray: number[] | null;
declare borderOpacityWhenMoving: number;
declare borderScaleFactor: number;
declare hasBorders: boolean;
declare selectionBackgroundColor: string;
declare selectable: boolean;
declare evented: boolean;
declare perPixelTargetFind: boolean;
declare activeOn: 'down' | 'up';
declare hoverCursor: CSSStyleDeclaration['cursor'] | null;
declare moveCursor: CSSStyleDeclaration['cursor'] | null;
/**

@@ -62,13 +111,2 @@ * Describe object's corner position in canvas element coordinates.

/**
* When `true`, cache does not get updated during scaling. The picture will get blocky if scaled
* too much and will be redrawn with correct details at the end of scaling.
* this setting is performance and application dependant.
* default to true
* since 1.7.0
* @type Boolean
* @default true
*/
declare noScaleCache: boolean;
/**
* keeps the value of the last hovered corner during mouse move.

@@ -91,15 +129,2 @@ * 0 is no corner, or 'mt', 'ml', 'mtr' etc..

/**
* The angle that an object will lock to while rotating.
* @type [TDegree]
*/
declare snapAngle?: TDegree;
/**
* The angle difference from the current snapped angle in which snapping should occur.
* When undefined, the snapThreshold will default to the snapAngle.
* @type [TDegree]
*/
declare snapThreshold?: TDegree;
/**
* holds the controls for the object.

@@ -128,8 +153,10 @@ * controls are added by default_controls.js

/**
* Constructor
* @param {Object} [options] Options object
*/
constructor(options?: Record<string, unknown>) {
super(options);
static ownDefaults: Record<string, any> = interactiveDefaults;
static getDefaults(): Record<string, any> {
return {
...super.getDefaults(),
controls: createObjectDefaultControls(),
...InteractiveFabricObject.ownDefaults,
};
}

@@ -148,6 +175,3 @@

action = targetCanvas._currentTransform.action;
if (
this === (target as InteractiveFabricObject) &&
action.startsWith('scale')
) {
if (this === (target as unknown as this) && action.startsWith('scale')) {
return false;

@@ -160,7 +184,11 @@ }

/**
* Determines which corner has been clicked
* Determines which corner is under the mouse cursor, represented by `pointer`.
* This function is return a corner only if the object is the active one.
* This is done to avoid selecting corner of non active object and activating transformations
* rather than drag action. The default behavior of fabricJS is that if you want to transform
* an object, first you select it to show the control set
* @private
* @param {Object} pointer The pointer indicating the mouse position
* @param {boolean} forTouch indicates if we are looking for interaction area with a touch action
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or 0 if nothing is found.
*/

@@ -171,3 +199,3 @@ _findTargetCorner(pointer: Point, forTouch = false): 0 | string {

!this.canvas ||
(this.canvas._activeObject as InteractiveFabricObject) !== this
(this.canvas._activeObject as unknown as this) !== this
) {

@@ -337,4 +365,3 @@ return 0;

(this.canvas && !this.canvas.interactive) ||
(this.canvas &&
(this.canvas._activeObject as InteractiveFabricObject) !== this)
(this.canvas && (this.canvas._activeObject as unknown as this) !== this)
) {

@@ -341,0 +368,0 @@ return;

@@ -9,3 +9,2 @@ import { cache } from '../../cache';

import type {
TClassProperties,
TDegree,

@@ -16,6 +15,5 @@ TFiller,

} from '../../typedefs';
import { classRegistry } from '../../util/class_registry';
import { classRegistry } from '../../ClassRegistry';
import { runningAnimations } from '../../util/animation/AnimationRegistry';
import { cloneDeep } from '../../util/internals/cloneDeep';
import { capitalize } from '../../util/lang_string';
import { capValue } from '../../util/misc/capValue';

@@ -29,3 +27,4 @@ import { createCanvasElement, toDataURL } from '../../util/misc/dom';

} from '../../util/misc/objectTransforms';
import { pick } from '../../util/misc/pick';
import { sendObjectToPlane } from '../../util/misc/planeChange';
import { pick, pickBy } from '../../util/misc/pick';
import { toFixed } from '../../util/misc/toFixed';

@@ -44,2 +43,5 @@ import type { Group } from '../Group';

import type { Canvas } from '../../canvas/Canvas';
import { SerializedObjectProps } from './types/SerializedObjectProps';
import { ObjectProps } from './types/ObjectProps';
import { TProps } from './types';

@@ -90,382 +92,41 @@ export type TCachedFabricObject = FabricObject &

export class FabricObject<
EventSpec extends ObjectEvents = ObjectEvents
> extends AnimatableObject<EventSpec> {
declare type: string;
Props extends TProps<ObjectProps> = Partial<ObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends AnimatableObject<EventSpec>
implements ObjectProps
{
declare minScaleLimit: number;
/**
* Opacity of an object
* @type Number
* @default 1
*/
declare opacity: number;
/**
* Size of object's controlling corners (in pixels)
* @type Number
* @default 13
*/
declare cornerSize: number;
/**
* Size of object's controlling corners when touch interaction is detected
* @type Number
* @default 24
*/
declare touchCornerSize: number;
/**
* When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)
* @type Boolean
* @default true
*/
declare transparentCorners: boolean;
/**
* Default cursor value used when hovering over this object on canvas
* @type CSSStyleDeclaration['cursor'] | null
* @default null
*/
declare hoverCursor: CSSStyleDeclaration['cursor'] | null;
/**
* Default cursor value used when moving this object on canvas
* @type CSSStyleDeclaration['cursor'] | null
* @default null
*/
declare moveCursor: CSSStyleDeclaration['cursor'] | null;
/**
* Color of controlling borders of an object (when it's active)
* @type String
* @default rgb(178,204,255)
*/
declare borderColor: string;
/**
* Array specifying dash pattern of an object's borders (hasBorder must be true)
* @since 1.6.2
* @type Array | null
* default null;
*/
declare borderDashArray: number[] | null;
/**
* Color of controlling corners of an object (when it's active)
* @type String
* @default rgb(178,204,255)
*/
declare cornerColor: string;
/**
* Color of controlling corners of an object (when it's active and transparentCorners false)
* @since 1.6.2
* @type String
* @default null
*/
declare cornerStrokeColor: string;
/**
* Specify style of control, 'rect' or 'circle'
* This is deprecated. In the futuer there will be a standard control render
* And you can swap it with one of the alternative proposed with the control api
* @since 1.6.2
* @type 'rect' | 'circle'
* @default rect
* @deprecated
*/
declare cornerStyle: 'rect' | 'circle';
/**
* Array specifying dash pattern of an object's control (hasBorder must be true)
* @since 1.6.2
* @type Array | null
*/
declare cornerDashArray: number[] | null;
/**
* When true, this object will use center point as the origin of transformation
* when being scaled via the controls.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
declare centeredScaling: false;
/**
* When true, this object will use center point as the origin of transformation
* when being rotated via the controls.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
declare centeredRotation: true;
/**
* When defined, an object is rendered via stroke and this property specifies its color
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default null
*/
declare stroke: string | TFiller | null;
/**
* Color of object's fill
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default rgb(0,0,0)
*/
declare paintFirst: 'fill' | 'stroke';
declare fill: string | TFiller | null;
/**
* Fill rule used to fill an object
* accepted values are nonzero, evenodd
* <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `globalCompositeOperation` instead)
* @type String
* @default nonzero
*/
declare fillRule: CanvasFillRule;
/**
* Composite rule used for canvas globalCompositeOperation
* @type String
* @default
*/
declare globalCompositeOperation: GlobalCompositeOperation;
/**
* Background color of an object.
* takes css colors https://www.w3.org/TR/css-color-3/
* @type String
* @default
*/
declare backgroundColor: string;
/**
* Selection Background color of an object. colored layer behind the object when it is active.
* does not mix good with globalCompositeOperation methods.
* @type String
* @deprecated
* @default
*/
declare selectionBackgroundColor: string;
/**
* Array specifying dash pattern of an object's stroke (stroke must be defined)
* @type Array
* @default null;
*/
declare stroke: string | TFiller | null;
declare strokeDashArray: number[] | null;
/**
* Line offset of an object's stroke
* @type Number
* @default 0
*/
declare strokeDashOffset: number;
/**
* Line endings style of an object's stroke (one of "butt", "round", "square")
* @type String
* @default butt
*/
declare strokeLineCap: CanvasLineCap;
/**
* Corner style of an object's stroke (one of "bevel", "round", "miter")
* @type String
* @default
*/
declare strokeLineJoin: CanvasLineJoin;
/**
* Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke
* @type Number
* @default 4
*/
declare strokeMiterLimit: number;
/**
* Shadow object representing shadow of this shape
* @type Shadow
* @default null
*/
declare globalCompositeOperation: GlobalCompositeOperation;
declare backgroundColor: string;
declare shadow: Shadow | null;
/**
* Opacity of object's controlling borders when object is active and moving
* @type Number
* @default 0.4
*/
declare borderOpacityWhenMoving: number;
/**
* Scale factor of object's controlling borders
* bigger number will make a thicker border
* border is 1, so this is basically a border thickness
* since there is no way to change the border itself.
* @type Number
* @default 1
*/
declare borderScaleFactor: number;
/**
* Minimum allowed scale value of an object
* @type Number
* @default 0
*/
declare minScaleLimit: number;
/**
* When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).
* But events still fire on it.
* @type Boolean
* @default
*/
declare selectable: boolean;
/**
* When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4
* @type Boolean
* @default
*/
declare evented: boolean;
/**
* When set to `false`, an object is not rendered on canvas
* @type Boolean
* @default
*/
declare visible: boolean;
/**
* When set to `false`, object's controls are not displayed and can not be used to manipulate object
* @type Boolean
* @default
*/
declare hasControls: boolean;
/**
* When set to `false`, object's controlling borders are not rendered
* @type Boolean
* @default
*/
declare hasBorders: boolean;
/**
* When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
* @type Boolean
* @default
*/
declare perPixelTargetFind: boolean;
/**
* When `false`, default object's values are not included in its serialization
* @type Boolean
* @default
*/
declare includeDefaultValues: boolean;
/**
* When `true`, object horizontal movement is locked
* @type Boolean
* @default
*/
declare lockMovementX: boolean;
/**
* When `true`, object vertical movement is locked
* @type Boolean
* @default
*/
declare lockMovementY: boolean;
/**
* When `true`, object rotation is locked
* @type Boolean
* @default
*/
declare lockRotation: boolean;
/**
* When `true`, object horizontal scaling is locked
* @type Boolean
* @default
*/
declare lockScalingX: boolean;
/**
* When `true`, object vertical scaling is locked
* @type Boolean
* @default
*/
declare lockScalingY: boolean;
/**
* When `true`, object horizontal skewing is locked
* @type Boolean
* @default
*/
declare lockSkewingX: boolean;
/**
* When `true`, object vertical skewing is locked
* @type Boolean
* @default
*/
declare lockSkewingY: boolean;
/**
* When `true`, object cannot be flipped by scaling into negative values
* @type Boolean
* @default
*/
declare lockScalingFlip: boolean;
/**
* When `true`, object is not exported in OBJECT/JSON
* @since 1.6.3
* @type Boolean
* @default
*/
declare excludeFromExport: boolean;
/**
* When `true`, object is cached on an additional canvas.
* When `false`, object is not cached unless necessary ( clipPath )
* default to true
* @since 1.7.0
* @type Boolean
* @default true
*/
declare objectCaching: boolean;
/**
* When set to `true`, object's cache will be rerendered next render call.
* since 1.7.0
* @type Boolean
* @default true
*/
declare dirty: boolean;
declare clipPath?: FabricObject;
declare inverted: boolean;
declare absolutePositioned: boolean;
declare centeredRotation: boolean;
/**
* Determines if the fill or the stroke is drawn first (one of "fill" or "stroke")
* @type String
* @default
*/
declare paintFirst: 'fill' | 'stroke';
/**
* When 'down', object is set to active on mousedown/touchstart
* When 'up', object is set to active on mouseup/touchend
* Experimental. Let's see if this breaks anything before supporting officially
* @private
* since 4.4.0
* @type String
* @default 'down'
*/
declare activeOn: 'down' | 'up';
/**
* This list of properties is used to check if the state of an object is changed.

@@ -476,3 +137,3 @@ * This state change now is only used for children of groups to understand if a group

*/
declare stateProperties: string[];
static stateProperties: string[] = stateProperties;

@@ -486,35 +147,13 @@ /**

*/
declare cacheProperties: string[];
static cacheProperties: string[] = cacheProperties;
/**
* a fabricObject that, without stroke define a clipping area with their shape. filled in black
* the clipPath object gets used when the object has rendered, and the context is placed in the center
* of the object cacheCanvas.
* If you want 0,0 of a clipPath to align with an object center, use clipPath.originX/Y to 'center'
* @type FabricObject
* When set to `true`, object's cache will be rerendered next render call.
* since 1.7.0
* @type Boolean
* @default true
*/
declare clipPath?: FabricObject;
declare dirty: boolean;
/**
* Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will make the object clip to the outside of the clipPath
* since 2.4.0
* @type boolean
* @default false
*/
declare inverted: boolean;
/**
* Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will have its top and left relative to canvas, and will
* not be influenced by the object transform. This will make the clipPath relative
* to the canvas, but clipping just a particular object.
* WARNING this is beta, this feature may change or be renamed.
* since 2.4.0
* @type boolean
* @default false
*/
declare absolutePositioned: boolean;
/**
* Quick access for the _cacheCanvas rendering context

@@ -603,8 +242,2 @@ * This is part of the objectCaching feature

/**
* A reference to the parent of the object
* Used to keep the original parent ref when the object has been added to an ActiveSelection, hence loosing the `group` ref
*/
declare __owningGroup?: Group;
/**
* Indicate if the object is sitting on a cache dedicated to it

@@ -627,8 +260,39 @@ * or is part of a larger cache for many object ( a group for example)

static ownDefaults: Record<string, any> = fabricObjectDefaultValues;
static getDefaults(): Record<string, any> {
return { ...FabricObject.ownDefaults };
}
/**
* Legacy identifier of the class. Prefer using utils like isType or instanceOf
* Will be removed in fabric 7 or 8.
* The setter exists because is very hard to catch all the ways in which a type value
* could be set in the instance
* @TODO add sustainable warning message
* @type string
* @deprecated
*/
get type() {
const name = this.constructor.name;
if (name === 'FabricObject') {
return 'object';
}
return name.toLowerCase();
}
set type(value) {
console.warn('Setting type has no effect', value);
}
/**
* Constructor
* @param {Object} [options] Options object
*/
constructor(options?: Partial<TClassProperties<FabricObject>>) {
constructor(options: Props = {} as Props) {
super();
Object.assign(
this,
(this.constructor as typeof FabricObject).getDefaults()
);
this.setOptions(options);

@@ -835,6 +499,6 @@ }

* Returns an object representation of an instance
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @param {string[]} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @return {Object} Object representation of an instance
*/
toObject(propertiesToInclude?: string[]): Record<string, any> {
protected toObject(propertiesToInclude: any[] = []): any {
const NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS,

@@ -851,3 +515,3 @@ clipPathData =

...pick(this, propertiesToInclude as (keyof this)[]),
type: this.type,
type: this.constructor.name,
version: VERSION,

@@ -905,3 +569,3 @@ originX: this.originX,

*/
toDatalessObject(propertiesToInclude?: string[]) {
toDatalessObject(propertiesToInclude?: any[]): any {
// will be overwritten by subclasses

@@ -915,23 +579,27 @@ return this.toObject(propertiesToInclude);

*/
_removeDefaultValues(object: Record<string, any>) {
const prototype = classRegistry.getClass(object.type).prototype;
Object.keys(object).forEach(function (prop) {
if (prop === 'left' || prop === 'top' || prop === 'type') {
return;
_removeDefaultValues<T extends object>(object: T): Partial<T> {
// getDefaults() ( get from static ownDefaults ) should win over prototype since anyway they get assigned to instance
// ownDefault vs prototype is swappable only if you change all the fabric objects consistently.
const defaults = (this.constructor as typeof FabricObject).getDefaults();
const hasStaticDefaultValues = Object.keys(defaults).length > 0;
const baseValues = hasStaticDefaultValues
? defaults
: Object.getPrototypeOf(this);
return pickBy(object, (value, key) => {
if (key === 'left' || key === 'top' || key === 'type') {
return true;
}
if (object[prop] === prototype[prop]) {
delete object[prop];
}
// basically a check for [] === []
if (
Array.isArray(object[prop]) &&
Array.isArray(prototype[prop]) &&
object[prop].length === 0 &&
prototype[prop].length === 0
) {
delete object[prop];
}
const baseValue = baseValues[key];
return (
value !== baseValue &&
// basically a check for [] === []
!(
Array.isArray(value) &&
Array.isArray(baseValue) &&
value.length === 0 &&
baseValue.length === 0
)
);
});
return object;
}

@@ -944,3 +612,3 @@

toString() {
return `#<${capitalize(this.type)}>`;
return `#<${this.constructor.name}>`;
}

@@ -1012,3 +680,4 @@

/**
* @private
* Handles setting values on the instance and handling internal side effects
* @protected
* @param {String} key

@@ -1040,6 +709,11 @@ * @param {*} value

const groupNeedsUpdate = this.group && this.group.isOnACache();
if (this.cacheProperties.includes(key)) {
if (
(this.constructor as typeof FabricObject).cacheProperties.includes(key)
) {
this.dirty = true;
groupNeedsUpdate && this.group!.set('dirty', true);
} else if (groupNeedsUpdate && this.stateProperties.includes(key)) {
} else if (
groupNeedsUpdate &&
(this.constructor as typeof FabricObject).stateProperties.includes(key)
) {
this.group!.set('dirty', true);

@@ -1631,6 +1305,5 @@ }

const objectForm = this.toObject(propertiesToInclude);
// todo ok understand this. is static or it isn't?
// TS is more an issue here than an helper.
// @ts-ignore
return this.constructor.fromObject(objectForm);
return (this.constructor as typeof FabricObject).fromObject(
objectForm
) as unknown as this;
}

@@ -1675,2 +1348,3 @@

* @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2
* @param {Boolean} [options.viewportTransform] Account for canvas viewport transform
* @return {HTMLCanvasElement} Returns DOM element <canvas> with the FabricObject

@@ -1694,2 +1368,5 @@ */

}
if (options.viewportTransform) {
sendObjectToPlane(this, this.getViewportTransform());
}

@@ -1779,3 +1456,3 @@ const el = createCanvasElement(),

/**
* Returns true if specified type is identical to the type of an instance
* Returns true if any of the specified types is identical to the type of an instance
* @param {String} type Type to check against

@@ -1785,3 +1462,3 @@ * @return {Boolean}

isType(...types: string[]) {
return types.includes(this.type);
return types.includes(this.constructor.name) || types.includes(this.type);
}

@@ -1852,7 +1529,5 @@

dispose() {
// todo verify this.
// runningAnimations is always truthy
if (runningAnimations) {
runningAnimations.cancelByTarget(this);
}
runningAnimations.cancelByTarget(this);
this.off();
this._set('canvas', undefined);
}

@@ -1869,3 +1544,3 @@

*/
static _fromObject(
static _fromObject<S extends FabricObject>(
object: Record<string, unknown>,

@@ -1876,3 +1551,3 @@ {

}: { extraParam?: string; signal?: AbortSignal } = {}
): Promise<FabricObject> {
): Promise<S> {
return enlivenObjectEnlivables<any>(cloneDeep(object), options).then(

@@ -1884,3 +1559,3 @@ (enlivedMap) => {

if (extraParam) {
const { [extraParam]: arg0, ...rest } = allOptions;
const { [extraParam]: arg0, type, ...rest } = allOptions;
// @ts-ignore;

@@ -1892,3 +1567,3 @@ return new this(arg0, rest);

}
);
) as Promise<S>;
}

@@ -1903,6 +1578,6 @@

*/
static fromObject(
object: Record<string, unknown>,
static fromObject<T extends TProps<SerializedObjectProps>>(
object: T,
options?: { signal?: AbortSignal }
): Promise<FabricObject> {
) {
return this._fromObject(object, options);

@@ -1912,13 +1587,3 @@ }

/*
* Properties that at minimum needs to stay on the prototype
* That shouldn't be either on the instance and that can't be used as static
* For inheritance reasons ( used in the superclass but static in the subclass )
*/
Object.assign(FabricObject.prototype, {
cacheProperties,
stateProperties,
...fabricObjectDefaultValues,
});
classRegistry.setClass(FabricObject);
classRegistry.setClass(FabricObject, 'object');

@@ -28,2 +28,3 @@ import type {

import { ObjectEvents } from '../../EventTypeDefs';
import { ControlProps } from './types/ControlProps';

@@ -49,24 +50,6 @@ type TLineDescriptor = {

export class ObjectGeometry<
EventSpec extends ObjectEvents = ObjectEvents
> extends ObjectOrigin<EventSpec> {
/**
* When true, an object is rendered as flipped horizontally
* @type Boolean
* @default false
*/
declare flipX: boolean;
/**
* When true, an object is rendered as flipped vertically
* @type Boolean
* @default false
*/
declare flipY: boolean;
/**
* Padding between object and its controlling borders (in pixels)
* @type Number
* @default 0
*/
export class ObjectGeometry<EventSpec extends ObjectEvents = ObjectEvents>
extends ObjectOrigin<EventSpec>
implements Pick<ControlProps, 'padding'>
{
declare padding: number;

@@ -73,0 +56,0 @@

@@ -9,101 +9,23 @@ import { Point } from '../../Point';

import { resolveOrigin } from '../../util/misc/resolveOrigin';
import { BaseProps } from './types/BaseProps';
import { FillStrokeProps } from './types/FillStrokeProps';
export class ObjectOrigin<EventSpec> extends CommonMethods<EventSpec> {
/**
* Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}
* @type Number
* @default 0
*/
export class ObjectOrigin<EventSpec>
extends CommonMethods<EventSpec>
implements BaseProps, Pick<FillStrokeProps, 'strokeWidth' | 'strokeUniform'>
{
declare top: number;
/**
* Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}
* @type Number
* @default 0
*/
declare left: number;
/**
* Object width
* @type Number
* @default
*/
declare width: number;
/**
* Object height
* @type Number
* @default
*/
declare height: number;
/**
* Object scale factor (horizontal)
* @type Number
* @default 1
*/
declare flipX: boolean;
declare flipY: boolean;
declare scaleX: number;
/**
* Object scale factor (vertical)
* @type Number
* @default 1
*/
declare scaleY: number;
/**
* Angle of skew on x axes of an object (in degrees)
* @type Number
* @default 0
*/
declare skewX: number;
/**
* Angle of skew on y axes of an object (in degrees)
* @type Number
* @default 0
*/
declare skewY: number;
/**
* Horizontal origin of transformation of an object (one of "left", "right", "center")
* See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups
* @type String
* @default 'left'
*/
declare originX: TOriginX;
/**
* Vertical origin of transformation of an object (one of "top", "bottom", "center")
* See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups
* @type String
* @default 'top'
*/
declare originY: TOriginY;
/**
* Angle of rotation of an object (in degrees)
* @type Number
* @default 0
*/
declare angle: TDegree;
/**
* Width of a stroke used to render this object
* @type Number
* @default 1
*/
declare strokeWidth: number;
/**
* When `false`, the stoke width will scale with the object.
* When `true`, the stroke will always match the exact pixel size entered for stroke width.
* this Property does not work on Text classes or drawing call that uses strokeText,fillText methods
* default to false
* @since 2.6.0
* @type Boolean
* @default false
* @type Boolean
* @default false
*/
declare strokeUniform: boolean;

@@ -110,0 +32,0 @@

@@ -6,2 +6,3 @@ import { ObjectEvents } from '../../EventTypeDefs';

import { ObjectGeometry } from './ObjectGeometry';
import { isActiveSelection } from '../../util/types';

@@ -42,4 +43,21 @@ type TAncestor = StackedObject | Canvas | StaticCanvas;

/**
* A reference to the parent of the object
* Used to keep the original parent ref when the object has been added to an ActiveSelection, hence loosing the `group` ref
*/
declare __owningGroup?: Group;
/**
* Returns instance's parent **EXCLUDING** `ActiveSelection`
* @param {boolean} [strict] exclude canvas as well
*/
getParent<T extends boolean>(strict?: T): TAncestor | undefined {
return (
(isActiveSelection(this.group) ? this.__owningGroup : this.group) ||
(strict ? undefined : this.canvas)
);
}
/**
* Checks if object is descendant of target
* Should be used instead of @link {Collection.contains} for performance reasons
* Should be used instead of {@link Group.contains} or {@link StaticCanvas.contains} for performance reasons
* @param {TAncestor} target

@@ -49,13 +67,10 @@ * @returns {boolean}

isDescendantOf(target: TAncestor): boolean {
let parent = this.group || this.canvas;
while (parent) {
if (target === parent) {
return true;
} else if (parent instanceof StaticCanvas) {
// happens after all parents were traversed through without a match
return false;
}
parent = (parent as Group).group || (parent as Group).canvas;
}
return false;
return (
this.__owningGroup === target ||
this.group === target ||
this.canvas === target ||
// walk up
(!!this.__owningGroup && this.__owningGroup.isDescendantOf(target)) ||
(!!this.group && this.group.isDescendantOf(target))
);
}

@@ -66,13 +81,13 @@

* @param {boolean} [strict] returns only ancestors that are objects (without canvas)
* @returns {Ancestors} ancestors from bottom to top
* @returns {Ancestors} ancestors (excluding `ActiveSelection`) from bottom to top
*/
getAncestors<T extends boolean>(strict?: T): Ancestors<T> {
const ancestors: TAncestor[] = [];
let parent = this.group || (strict ? undefined : this.canvas);
while (parent) {
ancestors.push(parent);
// eslint-disable-next-line @typescript-eslint/no-this-alias
let parent: TAncestor | undefined = this;
do {
parent =
(parent as Group).group ||
(strict ? undefined : (parent as Group).canvas);
}
parent instanceof StackedObject ? parent.getParent(strict) : undefined;
parent && ancestors.push(parent);
} while (parent);
return ancestors as Ancestors<T>;

@@ -79,0 +94,0 @@ }

@@ -1,7 +0,5 @@

//@ts-nocheck
import { config } from '../config';
import { SHARED_ATTRIBUTES } from '../parser/attributes';
import { parseAttributes } from '../parser/parseAttributes';
import { Point } from '../Point';
import { PathData, TClassProperties } from '../typedefs';
import { Point, XY } from '../Point';
import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints';

@@ -14,8 +12,31 @@ import { toFixed } from '../util/misc/toFixed';

parsePath,
type TPathSegmentsInfo,
} from '../util/path';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import { TPathSegmentInfo, TSimplePathData } from '../util/path/typedefs';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
import { TClassProperties, TSVGReviver } from '../typedefs';
import { cloneDeep } from '../util/internals/cloneDeep';
export class Path extends FabricObject {
interface UniquePathProps {
sourcePath?: string;
path?: TSimplePathData;
}
export interface SerializedPathProps
extends SerializedObjectProps,
UniquePathProps {}
export interface PathProps extends FabricObjectProps, UniquePathProps {}
export class Path<
Props extends TProps<PathProps> = Partial<PathProps>,
SProps extends SerializedPathProps = SerializedPathProps,
EventSpec extends ObjectEvents = ObjectEvents
> extends FabricObject<Props, SProps, EventSpec> {
/**

@@ -26,3 +47,3 @@ * Array of path points

*/
declare path: PathData;
declare path: TSimplePathData;

@@ -35,7 +56,9 @@ declare pathOffset: Point;

declare segmentsInfo?: TPathSegmentsInfo[];
declare segmentsInfo?: TPathSegmentInfo[];
static cacheProperties = [...cacheProperties, 'path', 'fillRule'];
/**
* Constructor
* @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {TSimplePathData} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {Object} [options] Options object

@@ -45,6 +68,6 @@ * @return {Path} thisArg

constructor(
path: PathData | string,
{ path: _, left, top, ...options }: any = {}
path: TSimplePathData | string,
{ path: _, left, top, ...options }: Props = {} as Props
) {
super(options);
super(options as Props);
const pathTL = this._setPath(path || []);

@@ -63,7 +86,7 @@ const origin = this.translateToGivenOrigin(

* @private
* @param {PathData | string} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {TSimplePathData | string} path Path data (sequence of coordinates and corresponding "command" tokens)
* @param {boolean} [adjustPosition] pass true to reposition the object according to the bounding box
* @returns {Point} top left position of the bounding box, useful for complementary positioning
*/
_setPath(path: PathData | string, adjustPosition?: boolean) {
_setPath(path: TSimplePathData | string, adjustPosition?: boolean) {
this.path = makePathSimpler(Array.isArray(path) ? path : parsePath(path));

@@ -138,3 +161,2 @@ return this.setDimensions();

case 'z':
case 'Z':

@@ -160,3 +182,3 @@ x = subpathStartX;

* Returns string representation of an instance
* @return {String} string representation of an instance
* @return {string} string representation of an instance
*/

@@ -174,8 +196,9 @@ toString() {

*/
toObject(propertiesToInclude: (keyof this)[] = []) {
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return {
...super.toObject(propertiesToInclude),
path: this.path.map((item) => {
return item.slice();
}),
path: cloneDeep(this.path),
};

@@ -189,6 +212,10 @@ }

*/
toDatalessObject(propertiesToInclude: (keyof this)[] = []) {
const o = this.toObject(['sourcePath', ...propertiesToInclude]);
if (o.sourcePath) {
toDatalessObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
const o = this.toObject<T, K>(propertiesToInclude);
if (this.sourcePath) {
delete o.path;
o.sourcePath = this.sourcePath;
}

@@ -204,3 +231,3 @@ return o;

_toSVG() {
const path = joinPath(this.path);
const path = joinPath(this.path, config.NUM_FRACTION_DIGITS);
return [

@@ -224,5 +251,5 @@ '<path ',

* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
* @return {string} svg representation of an instance
*/
toClipPathSVG(reviver) {
toClipPathSVG(reviver: TSVGReviver) {
const additionalTransform = this._getOffsetTransform();

@@ -241,5 +268,5 @@ return (

* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
* @return {string} svg representation of an instance
*/
toSVG(reviver) {
toSVG(reviver: TSVGReviver) {
const additionalTransform = this._getOffsetTransform();

@@ -254,3 +281,3 @@ return this._createBaseSVGMarkup(this._toSVG(), {

* Returns number representation of an instance complexity
* @return {Number} complexity of this instance
* @return {number} complexity of this instance
*/

@@ -271,3 +298,3 @@ complexity() {

_calcDimensions() {
const bounds: Point[] = [];
const bounds: XY[] = [];
let subpathStartX = 0,

@@ -330,3 +357,2 @@ subpathStartY = 0,

case 'z':
case 'Z':

@@ -368,4 +394,4 @@ x = subpathStartX;

*/
static fromObject(object) {
return this._fromObject(object, {
static fromObject<T extends TProps<SerializedPathProps>>(object: T) {
return this._fromObject<Path>(object, {
extraParam: 'path',

@@ -384,3 +410,7 @@ });

*/
static fromElement(element, callback, options) {
static fromElement(
element: SVGElement,
callback: (path: Path) => void,
options: any
) {
const parsedAttributes = parseAttributes(element, this.ATTRIBUTE_NAMES);

@@ -400,11 +430,2 @@ callback(

export const pathDefaultValues: Partial<TClassProperties<Path>> = {
type: 'path',
};
Object.assign(Path.prototype, {
...pathDefaultValues,
cacheProperties: [...cacheProperties, 'path', 'fillRule'],
});
classRegistry.setClass(Path);

@@ -411,0 +432,0 @@ classRegistry.setSVGClass(Path);

@@ -1,6 +0,14 @@

import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { Polyline, polylineDefaultValues } from './Polyline';
export class Polygon extends Polyline {
static ownDefaults: Record<string, any> = polylineDefaultValues;
static getDefaults() {
return {
...super.getDefaults(),
...Polyline.ownDefaults,
};
}
protected isOpen() {

@@ -11,10 +19,3 @@ return false;

export const polygonDefaultValues: Partial<TClassProperties<Polygon>> = {
...polylineDefaultValues,
type: 'polygon',
};
Object.assign(Polygon.prototype, polygonDefaultValues);
classRegistry.setClass(Polygon);
classRegistry.setSVGClass(Polygon);

@@ -5,5 +5,5 @@ import { config } from '../config';

import { parsePointsAttribute } from '../parser/parsePointsAttribute';
import { IPoint, Point } from '../Point';
import { XY, Point } from '../Point';
import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints';

@@ -14,4 +14,23 @@ import { projectStrokeOnPoints } from '../util/misc/projectStroke';

import { FabricObject, cacheProperties } from './Object/FabricObject';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
import { cloneDeep } from '../util/internals/cloneDeep';
export class Polyline extends FabricObject {
export const polylineDefaultValues: Partial<TClassProperties<Polyline>> = {
exactBoundingBox: false,
};
export interface SerializedPolylineProps extends SerializedObjectProps {
points: XY[];
}
export class Polyline<
Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>,
SProps extends SerializedPolylineProps = SerializedPolylineProps,
EventSpec extends ObjectEvents = ObjectEvents
> extends FabricObject<Props, SProps, EventSpec> {
/**

@@ -22,3 +41,3 @@ * Points array

*/
declare points: IPoint[];
declare points: XY[];

@@ -38,2 +57,10 @@ /**

static ownDefaults: Record<string, any> = polylineDefaultValues;
static getDefaults() {
return {
...super.getDefaults(),
...Polyline.ownDefaults,
};
}
/**

@@ -43,3 +70,12 @@ * A list of properties that if changed trigger a recalculation of dimensions

*/
declare strokeBBoxAffectingProperties: (keyof this)[];
static layoutProperties: (keyof Polyline)[] = [
'skewX',
'skewY',
'strokeLineCap',
'strokeLineJoin',
'strokeMiterLimit',
'strokeWidth',
'strokeUniform',
'points',
];

@@ -52,2 +88,4 @@ declare fromSVG: boolean;

static cacheProperties = [...cacheProperties, 'points'];
/**

@@ -72,4 +110,5 @@ * Constructor

*/
constructor(points: IPoint[] = [], { left, top, ...options }: any = {}) {
constructor(points: XY[] = [], options: Props = {} as Props) {
super({ points, ...options });
const { left, top } = options;
this.initialized = true;

@@ -182,5 +221,9 @@ this.setBoundingBox(true);

this.strokeUniform &&
this.strokeBBoxAffectingProperties.includes('strokeUniform') &&
(this.constructor as typeof Polyline).layoutProperties.includes(
'strokeUniform'
) &&
this.strokeLineJoin !== 'round') ||
this.strokeBBoxAffectingProperties.includes(key as keyof this))
(this.constructor as typeof Polyline).layoutProperties.includes(
key as keyof Polyline
))
) {

@@ -197,6 +240,9 @@ this.setDimensions();

*/
toObject(propertiesToInclude?: string[]): object {
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return {
...super.toObject(propertiesToInclude),
points: this.points.concat(),
points: cloneDeep(this.points),
};

@@ -225,3 +271,3 @@ }

return [
`<${this.type} `,
`<${this.constructor.name.toLowerCase() as 'polyline' | 'polygon'} `,
'COMMON_PARTS',

@@ -315,4 +361,4 @@ `points="${points.join('')}" />\n`,

*/
static fromObject(object: Record<string, unknown>) {
return this._fromObject(object, {
static fromObject<T extends TProps<SerializedPolylineProps>>(object: T) {
return this._fromObject<Polyline>(object, {
extraParam: 'points',

@@ -323,23 +369,3 @@ });

export const polylineDefaultValues: Partial<TClassProperties<Polyline>> = {
type: 'polyline',
exactBoundingBox: false,
};
Object.assign(Polyline.prototype, {
...polylineDefaultValues,
cacheProperties: [...cacheProperties, 'points'],
strokeBBoxAffectingProperties: [
'skewX',
'skewY',
'strokeLineCap',
'strokeLineJoin',
'strokeMiterLimit',
'strokeWidth',
'strokeUniform',
'points',
],
});
classRegistry.setClass(Polyline);
classRegistry.setSVGClass(Polyline);

@@ -5,6 +5,37 @@ import { kRect } from '../constants';

import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject, cacheProperties } from './Object/FabricObject';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export class Rect extends FabricObject {
export const rectDefaultValues: Partial<TClassProperties<Rect>> = {
rx: 0,
ry: 0,
};
interface UniqueRectProps {
rx: number;
ry: number;
}
export interface SerializedRectProps
extends SerializedObjectProps,
UniqueRectProps {}
export interface RectProps extends FabricObjectProps, UniqueRectProps {}
const RECT_PROPS = ['rx', 'ry'] as const;
export class Rect<
Props extends TProps<RectProps> = Partial<RectProps>,
SProps extends SerializedRectProps = SerializedRectProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements RectProps
{
/**

@@ -24,2 +55,13 @@ * Horizontal border radius

static cacheProperties = [...cacheProperties, ...RECT_PROPS];
static ownDefaults: Record<string, any> = rectDefaultValues;
static getDefaults(): Record<string, any> {
return {
...super.getDefaults(),
...Rect.ownDefaults,
};
}
/**

@@ -30,3 +72,3 @@ * Constructor

*/
constructor(options: Record<string, unknown>) {
constructor(options: Props) {
super(options);

@@ -112,4 +154,7 @@ this._initRxRy();

*/
toObject(propertiesToInclude: string[] = []) {
return super.toObject(['rx', 'ry', ...propertiesToInclude]);
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return super.toObject([...RECT_PROPS, ...propertiesToInclude]);
}

@@ -191,14 +236,3 @@

export const rectDefaultValues: Partial<TClassProperties<Rect>> = {
type: 'rect',
rx: 0,
ry: 0,
};
Object.assign(Rect.prototype, {
...rectDefaultValues,
cacheProperties: [...cacheProperties, 'rx', 'ry'],
});
classRegistry.setClass(Rect);
classRegistry.setSVGClass(Rect);

@@ -1,4 +0,11 @@

import { ObjectEvents } from '../../EventTypeDefs';
import type { ObjectEvents } from '../../EventTypeDefs';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from '../Object/types';
import { FabricObject } from '../Object/FabricObject';
import { styleProperties } from './constants';
// @TODO properly type this
export type TextStyleDeclaration = Record<string, any>;

@@ -11,8 +18,10 @@

export abstract class StyledText<
EventSpec extends ObjectEvents
> extends FabricObject<EventSpec> {
Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
> extends FabricObject<Props, SProps, EventSpec> {
declare abstract styles: TextStyle;
protected declare abstract _textLines: string[][];
protected declare abstract _forceClearCache: boolean;
protected declare abstract _styleProperties: string[];
protected declare _forceClearCache: boolean;
static _styleProperties = styleProperties;
abstract get2DCursorLocation(

@@ -264,5 +273,6 @@ selectionStart: number,

const style = this._getStyleDeclaration(lineIndex, charIndex) || {},
styleObject: TextStyleDeclaration = {};
for (let i = 0; i < this._styleProperties.length; i++) {
const prop = this._styleProperties[i];
styleObject: TextStyleDeclaration = {},
styleProps = (this.constructor as typeof StyledText)._styleProperties;
for (let i = 0; i < styleProps.length; i++) {
const prop = styleProps[i];
styleObject[prop] =

@@ -269,0 +279,0 @@ typeof style[prop] === 'undefined'

@@ -14,3 +14,3 @@ // @ts-nocheck

} from '../../typedefs';
import { classRegistry } from '../../util/class_registry';
import { classRegistry } from '../../ClassRegistry';
import { graphemeSplit } from '../../util/lang_string';

@@ -28,2 +28,12 @@ import { createCanvasElement } from '../../util/misc/dom';

import { applyMixins } from '../../util/applyMixins';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from '../Object/types';
import {
additionalProps,
textDefaultValues,
textLayoutProperties,
} from './constants';

@@ -43,2 +53,6 @@ let measuringContext: CanvasRenderingContext2D | null;

type TPathSide = 'left' | 'right';
type TPathAlign = 'baseline' | 'center' | 'ascender' | 'descender';
/**

@@ -64,23 +78,26 @@ * Measure and return the info of a single grapheme.

const additionalProps = [
'fontFamily',
'fontWeight',
'fontSize',
'text',
'underline',
'overline',
'linethrough',
'textAlign',
'fontStyle',
'lineHeight',
'textBackgroundColor',
'charSpacing',
'styles',
'direction',
'path',
'pathStartOffset',
'pathSide',
'pathAlign',
] as const;
// @TODO this is not complete
interface UniqueTextProps {
charSpacing: number;
lineHeight: number;
fontSize: number;
fontWeight: string;
fontFamily: string;
fontStyle: string;
pathSide: TPathSide;
pathAlign: TPathAlign;
underline: boolean;
overline: boolean;
linethrough: boolean;
textAlign: string;
direction: CanvasDirection;
path?: Path;
}
export interface SerializedTextProps
extends SerializedObjectProps,
UniqueTextProps {}
export interface TextProps extends FabricObjectProps, UniqueTextProps {}
/**

@@ -91,10 +108,15 @@ * Text class

export class Text<
EventSpec extends ObjectEvents = ObjectEvents
> extends StyledText<EventSpec> {
Props extends TProps<TextProps> = Partial<TextProps>,
SProps extends SerializedTextProps = SerializedTextProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends StyledText<Props, SProps, EventSpec>
implements UniqueTextProps
{
/**
* Properties which when set cause object to change dimensions
* @type Array
* @private
* Properties that requires a text layout recalculation when changed
* @type string[]
* @protected
*/
declare _dimensionAffectingProps: string[];
static textLayoutProperties: string[] = textLayoutProperties;

@@ -232,4 +254,2 @@ /**

protected declare _styleProperties: string[];
declare styles: TextStyle;

@@ -259,3 +279,3 @@

*/
declare path: Path;
declare path: Path | null;

@@ -273,6 +293,6 @@ /**

* Only used when text has a path
* @type {String} 'left|right'
* @type {TPathSide} 'left|right'
* @default
*/
declare pathSide: string;
declare pathSide: TPathSide;

@@ -284,6 +304,6 @@ /**

* This feature is in BETA, and its behavior may change
* @type String
* @type TPathAlign
* @default
*/
declare pathAlign: string;
declare pathAlign: TPathAlign;

@@ -330,6 +350,6 @@ /**

* @since 4.5.0
* @type {String} 'ltr|rtl'
* @type {CanvasDirection} 'ltr|rtl'
* @default
*/
declare direction: string;
declare direction: CanvasDirection;

@@ -377,6 +397,12 @@ /**

declare __lineWidths: number[];
declare _forceClearCache: boolean;
declare initialized?: true;
static cacheProperties = [...cacheProperties, ...additionalProps];
static ownDefaults: Record<string, any> = textDefaultValues;
static getDefaults() {
return { ...super.getDefaults(), ...Text.ownDefaults };
}
constructor(text: string, options: any) {

@@ -390,3 +416,2 @@ super({ ...options, text, styles: options?.styles || {} });

this.setCoords();
this.saveState({ propertySet: '_dimensionAffectingProps' });
}

@@ -426,2 +451,3 @@

this._clearCache();
this.dirty = true;
if (this.path) {

@@ -439,3 +465,2 @@ this.width = this.path.width;

}
this.saveState({ propertySet: '_dimensionAffectingProps' });
}

@@ -780,3 +805,3 @@

coupleWidth = fontCache[couple];
kernedWidth = coupleWidth - previousWidth;
kernedWidth = coupleWidth - previousWidth!;
}

@@ -1440,2 +1465,3 @@ if (

_clearCache() {
this._forceClearCache = false;
this.__lineWidths = [];

@@ -1447,15 +1473,2 @@ this.__lineHeights = [];

/**
* @private
*/
_shouldClearDimensionCache() {
const shouldClear =
this._forceClearCache || this.hasStateChanged('_dimensionAffectingProps');
if (shouldClear) {
this.dirty = true;
this._forceClearCache = false;
}
return shouldClear;
}
/**
* Measure a single line given its index. Used to calculate the initial

@@ -1646,3 +1659,3 @@ * text bounding box. The values are calculated and stored in __lineWidths cache.

}
if (this._shouldClearDimensionCache()) {
if (this._forceClearCache) {
this.initDimensions();

@@ -1693,3 +1706,6 @@ }

*/
toObject(propertiesToInclude: (keyof this)[] = []) {
toObject<
T extends Omit<Props & TClassProperties<this>, keyof SProps>,
K extends keyof T = never
>(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
return {

@@ -1703,2 +1719,3 @@ ...super.toObject([...additionalProps, ...propertiesToInclude]),

set(key: string | any, value?: any) {
const { textLayoutProperties } = this.constructor as typeof Text;
super.set(key, value);

@@ -1712,8 +1729,7 @@ let needsDims = false;

}
needsDims =
needsDims || this._dimensionAffectingProps.indexOf(_key) !== -1;
needsDims = needsDims || textLayoutProperties.includes(_key);
isAddingPath = isAddingPath || _key === 'path';
}
} else {
needsDims = this._dimensionAffectingProps.indexOf(key) !== -1;
needsDims = textLayoutProperties.includes(key);
isAddingPath = key === 'path';

@@ -1874,4 +1890,4 @@ }

*/
static fromObject(object: Record<string, any>): Promise<Text> {
return this._fromObject(
static fromObject<T extends TProps<SerializedTextProps>>(object: T) {
return this._fromObject<Text>(
{

@@ -1888,84 +1904,4 @@ ...object,

// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype
// regexes, list of properties that are not suppose to change by instances, magic consts.
// this will be a separated effort
export const textDefaultValues: Partial<TClassProperties<Text>> = {
_dimensionAffectingProps: [
'fontSize',
'fontWeight',
'fontFamily',
'fontStyle',
'lineHeight',
'text',
'charSpacing',
'textAlign',
'styles',
'path',
'pathStartOffset',
'pathSide',
'pathAlign',
],
_styleProperties: [
'stroke',
'strokeWidth',
'fill',
'fontFamily',
'fontSize',
'fontWeight',
'fontStyle',
'underline',
'overline',
'linethrough',
'deltaY',
'textBackgroundColor',
],
_reNewline: /\r?\n/,
_reSpacesAndTabs: /[ \t\r]/g,
_reSpaceAndTab: /[ \t\r]/,
_reWords: /\S+/g,
type: 'text',
fontSize: 40,
fontWeight: 'normal',
fontFamily: 'Times New Roman',
underline: false,
overline: false,
linethrough: false,
textAlign: 'left',
fontStyle: 'normal',
lineHeight: 1.16,
superscript: {
size: 0.6, // fontSize factor
baseline: -0.35, // baseline-shift factor (upwards)
},
subscript: {
size: 0.6, // fontSize factor
baseline: 0.11, // baseline-shift factor (downwards)
},
textBackgroundColor: '',
cacheProperties: [...cacheProperties, ...additionalProps],
stroke: null,
shadow: null,
path: null,
pathStartOffset: 0,
pathSide: 'left',
pathAlign: 'baseline',
_fontSizeFraction: 0.222,
offsets: {
underline: 0.1,
linethrough: -0.315,
overline: -0.88,
},
_fontSizeMult: 1.13,
charSpacing: 0,
styles: null,
deltaY: 0,
direction: 'ltr',
CACHE_FONT_SIZE: 400,
MIN_TEXT_WIDTH: 2,
};
Object.assign(Text.prototype, textDefaultValues);
applyMixins(Text, [TextSVGExportMixin]);
classRegistry.setClass(Text);
classRegistry.setSVGClass(Text);
// @ts-nocheck
import { TClassProperties } from '../typedefs';
import { IText } from './IText/IText';
import { textDefaultValues } from './Text/Text';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { createTextboxDefaultControls } from '../controls/commonControls';
// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype
// regexes, list of properties that are not suppose to change by instances, magic consts.
// this will be a separated effort
export const textboxDefaultValues: Partial<TClassProperties<Textbox>> = {
minWidth: 20,
dynamicMinWidth: 2,
lockScalingFlip: true,
noScaleCache: false,
_wordJoiners: /[ \t\r]/,
splitByGrapheme: false,
};
/**

@@ -38,2 +50,14 @@ * Textbox class, based on IText, allows the user to resize the text rectangle

static textLayoutProperties = [...IText.textLayoutProperties, 'width'];
static ownDefaults: Record<string, any> = textboxDefaultValues;
static getDefaults() {
return {
...super.getDefaults(),
controls: createTextboxDefaultControls(),
...Textbox.ownDefaults,
};
}
/**

@@ -65,3 +89,2 @@ * Unlike superclass's version of this function, Textbox does not update

this.height = this.calcTextHeight();
this.saveState({ propertySet: '_dimensionAffectingProps' });
}

@@ -456,19 +479,2 @@

// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype
// regexes, list of properties that are not suppose to change by instances, magic consts.
// this will be a separated effort
export const textboxDefaultValues: Partial<TClassProperties<Textbox>> = {
type: 'textbox',
minWidth: 20,
dynamicMinWidth: 2,
lockScalingFlip: true,
noScaleCache: false,
_dimensionAffectingProps:
textDefaultValues._dimensionAffectingProps!.concat('width'),
_wordJoiners: /[ \t\r]/,
splitByGrapheme: false,
};
Object.assign(Textbox.prototype, textboxDefaultValues);
classRegistry.setClass(Textbox);

@@ -1,6 +0,29 @@

import { TClassProperties } from '../typedefs';
import { classRegistry } from '../util/class_registry';
import { classRegistry } from '../ClassRegistry';
import { FabricObject } from './Object/FabricObject';
import type {
FabricObjectProps,
SerializedObjectProps,
TProps,
} from './Object/types';
import type { ObjectEvents } from '../EventTypeDefs';
export class Triangle extends FabricObject {
export const triangleDefaultValues = {
width: 100,
height: 100,
};
export class Triangle<
Props extends TProps<FabricObjectProps> = Partial<FabricObjectProps>,
SProps extends SerializedObjectProps = SerializedObjectProps,
EventSpec extends ObjectEvents = ObjectEvents
>
extends FabricObject<Props, SProps, EventSpec>
implements FabricObjectProps
{
static ownDefaults: Record<string, any> = triangleDefaultValues;
static getDefaults() {
return { ...super.getDefaults(), ...Triangle.ownDefaults };
}
/**

@@ -36,11 +59,3 @@ * @private

export const triangleDefaultValues: Partial<TClassProperties<Triangle>> = {
type: 'triangle',
width: 100,
height: 100,
};
Object.assign(Triangle.prototype, triangleDefaultValues);
classRegistry.setClass(Triangle);
classRegistry.setSVGClass(Triangle);

@@ -5,4 +5,3 @@ // https://www.typescriptlang.org/docs/handbook/utility-types.html

import type { Pattern } from './Pattern';
import type { Point } from './Point';
import type { FabricObject } from './shapes/Object/FabricObject';
import type { XY, Point } from './Point';

@@ -15,4 +14,4 @@ interface NominalTag<T> {

// eslint-disable-next-line @typescript-eslint/ban-types
type TNonFunctionPropertyNames<T> = {
// eslint-disable-next-line @typescript-eslint/ban-types
[K in keyof T]: T[K] extends Function ? never : K;

@@ -73,7 +72,2 @@ }[keyof T];

/**
* SVG path commands
*/
export type PathData = (string | number)[][];
/**
* An invalid keyword and an empty string will be handled as the `anonymous` keyword.

@@ -107,2 +101,4 @@ * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes

export type TRectBounds = [min: XY, max: XY];
export type TToCanvasElementOptions = {

@@ -109,0 +105,0 @@ left?: number;

@@ -1,28 +0,9 @@

import { getEnv } from '../../env';
import { getWindow } from '../../env';
let _requestAnimFrame: AnimationFrameProvider['requestAnimationFrame'];
let _cancelAnimFrame: AnimationFrameProvider['cancelAnimationFrame'];
/**
* requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method
* @param {Function} callback Callback to invoke
*/
export function requestAnimFrame(callback: FrameRequestCallback): number {
if (!_requestAnimFrame) {
_requestAnimFrame =
getEnv().window.requestAnimationFrame ||
function requestAnimationFramePolyfill(callback: FrameRequestCallback) {
return getEnv().window.setTimeout(callback, 1000 / 60);
};
}
return _requestAnimFrame.call(getEnv().window, callback);
return getWindow().requestAnimationFrame(callback);
}
export function cancelAnimFrame(handle: number): void {
if (!_cancelAnimFrame) {
_cancelAnimFrame =
getEnv().window.cancelAnimationFrame || getEnv().window.clearTimeout;
}
return _cancelAnimFrame.call(getEnv().window, handle);
return getWindow().cancelAnimationFrame(handle);
}

@@ -1,5 +0,3 @@

//@ts-nocheck
import { getDocument } from '../env';
import { getEnv } from '../env';
/**

@@ -12,3 +10,3 @@ * Wraps element with another element

*/
export function wrapElement(element, wrapper) {
export function wrapElement(element: HTMLElement, wrapper: HTMLDivElement) {
if (element.parentNode) {

@@ -26,8 +24,8 @@ element.parentNode.replaceChild(wrapper, element);

*/
export function getScrollLeftTop(element) {
export function getScrollLeftTop(element: HTMLElement) {
let left = 0,
top = 0;
const docElement = getEnv().document.documentElement,
body = getEnv().document.body || {
const docElement = getDocument().documentElement,
body = getDocument().body || {
scrollLeft: 0,

@@ -40,7 +38,9 @@ scrollTop: 0,

// it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938
// @ts-ignore
while (element && (element.parentNode || element.host)) {
// Set element to element parent, or 'host' in case of ShadowDOM
// @ts-ignore
element = element.parentNode || element.host;
if (element === getEnv().document) {
// @ts-expect-error because element is typed as HTMLElement but it can go up to document
if (element === getDocument()) {
left = body.scrollLeft || docElement.scrollLeft || 0;

@@ -66,3 +66,3 @@ top = body.scrollTop || docElement.scrollTop || 0;

*/
export function getElementOffset(element) {
export function getElementOffset(element: HTMLElement) {
let box = { left: 0, top: 0 };

@@ -76,3 +76,3 @@ const doc = element && element.ownerDocument,

paddingTop: 'top',
};
} as const;

@@ -82,7 +82,5 @@ if (!doc) {

}
const elemStyle = getEnv().document.defaultView.getComputedStyle(
element,
null
);
const elemStyle = getDocument().defaultView!.getComputedStyle(element, null);
for (const attr in offsetAttributes) {
// @ts-expect-error TS learn to iterate!
offset[offsetAttributes[attr]] += parseInt(elemStyle[attr], 10) || 0;

@@ -110,3 +108,3 @@ }

*/
export function makeElementUnselectable(element) {
export function makeElementUnselectable(element: HTMLElement) {
if (typeof element.onselectstart !== 'undefined') {

@@ -124,3 +122,3 @@ element.onselectstart = () => false;

*/
export function makeElementSelectable(element) {
export function makeElementSelectable(element: HTMLElement) {
if (typeof element.onselectstart !== 'undefined') {

@@ -132,16 +130,1 @@ element.onselectstart = null;

}
export function cleanUpJsdomNode(element) {
if (!getEnv().isLikelyNode) {
return;
}
const impl = getEnv().jsdomImplForWrapper(element);
if (impl) {
impl._image = null;
impl._canvas = null;
// unsure if necessary
impl._currentSrc = null;
impl._attributes = null;
impl._classList = null;
}
}
// @ts-nocheck
import { getEnv } from '../env';
import { getWindow } from '../env';
import { noop } from '../constants';

@@ -20,3 +20,3 @@

onComplete = options.onComplete || noop,
xhr = new (getEnv().window.XMLHttpRequest)(),
xhr = new (getWindow().XMLHttpRequest)(),
body = options.body || options.parameters,

@@ -23,0 +23,0 @@ signal = options.signal,

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import { TBBox } from '../../typedefs';

@@ -6,6 +6,6 @@

* Calculates bounding box (left, top, width, height) from given `points`
* @param {IPoint[]} points
* @param {XY[]} points
* @return {Object} Object with left, top, width, height properties
*/
export const makeBoundingBoxFromPoints = (points: IPoint[]): TBBox => {
export const makeBoundingBoxFromPoints = (points: XY[]): TBBox => {
if (points.length === 0) {

@@ -12,0 +12,0 @@ return {

@@ -1,2 +0,2 @@

import { getEnv } from '../../env';
import { getDocument } from '../../env';
import { ImageFormat } from '../../typedefs';

@@ -8,3 +8,3 @@ /**

export const createCanvasElement = (): HTMLCanvasElement =>
getEnv().document.createElement('canvas');
getDocument().createElement('canvas');

@@ -16,3 +16,3 @@ /**

export const createImage = (): HTMLImageElement =>
getEnv().document.createElement('img');
getDocument().createElement('img');

@@ -19,0 +19,0 @@ /**

@@ -5,5 +5,5 @@ /**

* @param {CanvasRenderingContext2D} ctx context
* @param {Number} x x coordinate in canvasElementCoordinate, not fabric space
* @param {Number} y y coordinate in canvasElementCoordinate, not fabric space
* @param {Number} tolerance Tolerance pixels around the point, not alpha tolerance
* @param {Number} x x coordinate in canvasElementCoordinate, not fabric space. integer
* @param {Number} y y coordinate in canvasElementCoordinate, not fabric space. integer
* @param {Number} tolerance Tolerance pixels around the point, not alpha tolerance, integer
* @return {boolean} true if transparent

@@ -17,37 +17,14 @@ */

): boolean => {
// If tolerance is > 0 adjust start coords to take into account.
// If moves off Canvas fix to 0
if (tolerance > 0) {
if (x > tolerance) {
x -= tolerance;
} else {
x = 0;
}
if (y > tolerance) {
y -= tolerance;
} else {
y = 0;
}
}
tolerance = Math.round(tolerance);
const size = tolerance * 2 + 1;
const { data } = ctx.getImageData(x - tolerance, y - tolerance, size, size);
let _isTransparent = true;
const { data } = ctx.getImageData(
x,
y,
tolerance * 2 || 1,
tolerance * 2 || 1
);
const l = data.length;
// Split image data - for tolerance > 1, pixelDataSize = 4;
for (let i = 3; i < l; i += 4) {
for (let i = 3; i < data.length; i += 4) {
const alphaChannel = data[i];
if (alphaChannel > 0) {
// Stop if colour found
_isTransparent = false;
break;
return false;
}
}
return _isTransparent;
return true;
};
import { iMatrix } from '../../constants';
import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import { TDegree, TMat2D } from '../../typedefs';

@@ -39,3 +39,3 @@ import { cos } from './cos';

* Apply transform t to point p
* @param {Point | IPoint} p The point to transform
* @param {Point | XY} p The point to transform
* @param {Array} t The transform

@@ -46,3 +46,3 @@ * @param {Boolean} [ignoreOffset] Indicates that the offset should not be applied

export const transformPoint = (
p: IPoint,
p: XY,
t: TMat2D,

@@ -49,0 +49,0 @@ ignoreOffset?: boolean

@@ -7,3 +7,3 @@ import { noop } from '../../constants';

import { createImage } from './dom';
import { classRegistry } from '../class_registry';
import { classRegistry } from '../../ClassRegistry';

@@ -10,0 +10,0 @@ export type LoadImageOptions = {

@@ -18,1 +18,13 @@ /**

};
export const pickBy = <T extends Record<string, any>>(
source: T,
predicate: <K extends keyof T>(value: T[K], key: K, collection: T) => boolean
) => {
return (Object.keys(source) as (keyof T)[]).reduce((o, key) => {
if (predicate(source[key], key, source)) {
o[key] = source[key];
}
return o;
}, {} as Partial<T>);
};
import { iMatrix } from '../../constants';
import type { Point } from '../../Point';
import type { FabricObject } from '../../shapes/Object/FabricObject';
import type { FabricObject } from '../../shapes/Object/Object';
import type { TMat2D } from '../../typedefs';

@@ -5,0 +5,0 @@ import type { StaticCanvas } from '../../canvas/StaticCanvas';

@@ -1,2 +0,2 @@

import { IPoint } from '../../../Point';
import { XY } from '../../../Point';
import { StrokeLineCapProjections } from './StrokeLineCapProjections';

@@ -14,3 +14,3 @@ import { StrokeLineJoinProjections } from './StrokeLineJoinProjections';

export const projectStrokeOnPoints = (
points: IPoint[],
points: XY[],
options: TProjectStrokeOnPointsOptions,

@@ -26,3 +26,3 @@ openPath = false

points.forEach((A, index) => {
let B: IPoint, C: IPoint;
let B: XY, C: XY;
if (index === 0) {

@@ -29,0 +29,0 @@ C = points[1];

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { createVector, getOrthonormalVector, getUnitVector } from '../vectors';

@@ -29,3 +29,3 @@ import { StrokeLineJoinProjections } from './StrokeLineJoinProjections';

constructor(A: IPoint, T: IPoint, options: TProjectStrokeOnPointsOptions) {
constructor(A: XY, T: XY, options: TProjectStrokeOnPointsOptions) {
super(options);

@@ -32,0 +32,0 @@ this.A = new Point(A);

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { degreesToRadians } from '../radiansDegreesConversion';

@@ -37,8 +37,3 @@ import { getBisector, getOrthonormalVector, magnitude } from '../vectors';

constructor(
A: IPoint,
B: IPoint,
C: IPoint,
options: TProjectStrokeOnPointsOptions
) {
constructor(A: XY, B: XY, C: XY, options: TProjectStrokeOnPointsOptions) {
super(options);

@@ -45,0 +40,0 @@ this.A = new Point(A);

import { halfPI } from '../../../constants';
import { IPoint, Point } from '../../../Point';
import { XY, Point } from '../../../Point';
import { degreesToRadians } from '../radiansDegreesConversion';

@@ -39,3 +39,3 @@ import {

*/
protected createSideVector(from: IPoint, to: IPoint) {
protected createSideVector(from: XY, to: XY) {
const v = createVector(from, to);

@@ -42,0 +42,0 @@ return this.options.strokeUniform ? v.multiply(this.scale) : v;

@@ -60,4 +60,5 @@ import type {

if (!styles[i]) {
//no styles exist for this line, so add the line's length to the charIndex total
//no styles exist for this line, so add the line's length to the charIndex total and reset prevStyle
charIndex += textLines[i].length;
prevStyle = {};
continue;

@@ -64,0 +65,0 @@ }

@@ -1,2 +0,2 @@

import { IPoint, Point } from '../../Point';
import { XY, Point } from '../../Point';
import { TRadian } from '../../typedefs';

@@ -22,3 +22,3 @@

*/
export const createVector = (from: IPoint, to: IPoint): Point =>
export const createVector = (from: XY, to: XY): Point =>
new Point(to).subtract(from);

@@ -25,0 +25,0 @@

@@ -43,3 +43,3 @@ import type { ActiveSelection } from '../shapes/ActiveSelection';

): fabricObject is ActiveSelection => {
return !!fabricObject && fabricObject.type === 'activeSelection';
return !!fabricObject && fabricObject.isType('ActiveSelection');
};

@@ -52,3 +52,3 @@

// @todo discuss what to do and how to do
return !!fabricObject && fabricObject.type.includes('text');
return !!fabricObject && fabricObject.isType('Text', 'IText', 'Textbox');
};

@@ -61,3 +61,3 @@

// @todo discuss what to do and how to do
return !!fabricObject && ['i-text', 'textbox'].includes(fabricObject.type);
return !!fabricObject && fabricObject.isType('IText', 'Textbox');
};

@@ -64,0 +64,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc