Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(TS): canvas options #9140

Merged
merged 24 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## [next]

- chore(TS): mv + rename `TProps` => `TOptions` [#9139](https://github.com/fabricjs/fabric.js/pull/9139)
- chore(TS): BREAKING PREVIOUS BETA mv + rename `TProps` => `TOptions` [#9139](https://github.com/fabricjs/fabric.js/pull/9139)
- test(playwright): Use embedded eval from playwright [#9133](https://github.com/fabricjs/fabric.js/pull/9133)
- chore(TS): Fix event types and .once this binding [#9119](https://github.com/fabricjs/fabric.js/pull/9130)
- docs(): rm `canvas2pdf` [#9135](https://github.com/fabricjs/fabric.js/pull/9135)
Expand Down
2 changes: 2 additions & 0 deletions fabric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ export type {
TCanvasSizeOptions,
TSVGExportOptions,
} from './src/canvas/StaticCanvas';
export type { StaticCanvasOptions } from './src/canvas/StaticCanvasOptions';
export { StaticCanvas } from './src/canvas/StaticCanvas';
export { Canvas } from './src/canvas/Canvas';
export type { CanvasOptions } from './src/canvas/CanvasOptions';
export { CanvasDOMManager } from './src/canvas/DOMManagers/CanvasDOMManager';
export { StaticCanvasDOMManager } from './src/canvas/DOMManagers/StaticCanvasDOMManager';

Expand Down
14 changes: 7 additions & 7 deletions src/canvas/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import { Point } from '../Point';
import type { Group } from '../shapes/Group';
import type { IText } from '../shapes/IText/IText';
import type { FabricObject } from '../shapes/Object/FabricObject';
import type { TOptions } from '../typedefs';
import { isTouchEvent, stopEvent } from '../util/dom_event';
import { getDocumentFromElement, getWindowFromElement } from '../util/dom_misc';
import { sendPointToPlane } from '../util/misc/planeChange';
import {
isFabricObjectWithDragSupport,
isInteractiveTextObject,
} from '../util/typeAssertions';
import type { CanvasOptions } from './CanvasOptions';
import { SelectableCanvas } from './SelectableCanvas';
import { TextEditingManager } from './TextEditingManager';

Expand Down Expand Up @@ -64,19 +66,14 @@ type TSyntheticEventContext = {
drag: DragEventData;
};

export class Canvas extends SelectableCanvas {
export class Canvas extends SelectableCanvas implements CanvasOptions {
/**
* Contains the id of the touch event that owns the fabric transform
* @type Number
* @private
*/
declare mainTouchId: null | number;

/**
* When the option is enabled, PointerEvent is used instead of TPointerEvent.
* @type Boolean
* @default
*/
declare enablePointerEvents: boolean;

/**
Expand Down Expand Up @@ -117,7 +114,10 @@ export class Canvas extends SelectableCanvas {

textEditingManager = new TextEditingManager(this);

constructor(el: string | HTMLCanvasElement, options = {}) {
constructor(
el: string | HTMLCanvasElement,
options: TOptions<CanvasOptions> = {}
) {
super(el, options);
// bind event handlers
(
Expand Down
296 changes: 296 additions & 0 deletions src/canvas/CanvasOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
import type { ModifierKey, TOptionalModifierKey } from '../EventTypeDefs';
import type { TOptions } from '../typedefs';
import type { StaticCanvasOptions } from './StaticCanvasOptions';

export interface CanvasTransformOptions {
/**
* When true, objects can be transformed by one side (unproportionally)
* when dragged on the corners that normally would not do that.
* @type Boolean
* @default
* @since fabric 4.0 // changed name and default value
*/
uniformScaling: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In retrospective i don't like the idea of moving the documentation out of the classes themselves. I understand it makes files shorter but it seems the wrong solution.
\I know we did this already and is not new, but now i really dislike it.

Opening a class and being able to read is important to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you hover over a prop it shows the jsdoc.
I like it but that is why I kept it in separate commits... because I wanted to give you an easy way out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no if we go out we change them all. For now we keep consistency.
I know hovering works but reading is reading. It is also a vscode thing not an universal one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should I revert or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the jsdoc exist on the options as well?
For a dev the important place is on options so when creating a canvas ir object they see what it can do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @asturur, better a big module with everything related than death-by-thousand-files. While vscode hover documentation helps, there are many other occasions where it's useful to have things colocated in the same file, e.g. PR reviewing or debugging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend this book where the topic of "deep" modules is explained: https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201, i.e. a deep module with the relevant implementations all together (as far as the exposed public API is small) is better than many shallow modules that you need to put together in your mind in order to understand.


/**
* Indicates which key switches uniform scaling.
* values: 'altKey', 'shiftKey', 'ctrlKey'.
* If `null` or 'none' or any other string that is not a modifier key
* feature is disabled.
* totally wrong named. this sounds like `uniform scaling`
* if Canvas.uniformScaling is true, pressing this will set it to false
* and viceversa.
* @since 1.6.2
* @type ModifierKey
* @default
*/
uniScaleKey: TOptionalModifierKey;

/**
* When true, objects use center point as the origin of scale transformation.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
centeredScaling: boolean;

/**
* When true, objects use center point as the origin of rotate transformation.
* <b>Backwards incompatibility note:</b> This property replaces "centerTransform" (Boolean).
* @since 1.3.4
* @type Boolean
* @default
*/
centeredRotation: boolean;

/**
* Indicates which key enable centered Transform
* values: 'altKey', 'shiftKey', 'ctrlKey'.
* If `null` or 'none' or any other string that is not a modifier key
* feature is disabled feature disabled.
* @since 1.6.2
* @type ModifierKey
* @default
*/
centeredKey: TOptionalModifierKey;

/**
* Indicates which key enable alternate action on corner
* values: 'altKey', 'shiftKey', 'ctrlKey'.
* If `null` or 'none' or any other string that is not a modifier key
* feature is disabled feature disabled.
* @since 1.6.2
* @type ModifierKey
* @default
*/
altActionKey: TOptionalModifierKey;
}

export interface CanvasSelectionOptions {
/**
* Indicates whether group selection should be enabled
* @type Boolean
* @default
*/
selection: boolean;

/**
* Indicates which key or keys enable multiple click selection
* Pass value as a string or array of strings
* values: 'altKey', 'shiftKey', 'ctrlKey'.
* If `null` or empty or containing any other string that is not a modifier key
* feature is disabled.
* @since 1.6.2
* @type ModifierKey|ModifierKey[]
* @default
*/
selectionKey: TOptionalModifierKey | ModifierKey[];

/**
* Indicates which key enable alternative selection
* in case of target overlapping with active object
* values: 'altKey', 'shiftKey', 'ctrlKey'.
* For a series of reason that come from the general expectations on how
* things should work, this feature works only for preserveObjectStacking true.
* If `null` or 'none' or any other string that is not a modifier key
* feature is disabled.
* @since 1.6.5
* @type null|ModifierKey
* @default
*/
altSelectionKey: TOptionalModifierKey;

/**
* Color of selection
* @type String
* @default
*/
selectionColor: string;

/**
* Default dash array pattern
* If not empty the selection border is dashed
* @type Array
*/
selectionDashArray: number[];

/**
* Color of the border of selection (usually slightly darker than color of selection itself)
* @type String
* @default
*/
selectionBorderColor: string;

/**
* Width of a line used in object/group selection
* @type Number
* @default
*/
selectionLineWidth: number;

/**
* Select only shapes that are fully contained in the dragged selection rectangle.
* @type Boolean
* @default
*/
selectionFullyContained: boolean;
}

export interface CanvasCursorOptions {
/**
* Default cursor value used when hovering over an object on canvas
* @type CSSStyleDeclaration['cursor']
* @default move
*/
hoverCursor: CSSStyleDeclaration['cursor'];

/**
* Default cursor value used when moving an object on canvas
* @type CSSStyleDeclaration['cursor']
* @default move
*/
moveCursor: CSSStyleDeclaration['cursor'];

/**
* Default cursor value used for the entire canvas
* @type String
* @default default
*/
defaultCursor: CSSStyleDeclaration['cursor'];

/**
* Cursor value used during free drawing
* @type String
* @default crosshair
*/
freeDrawingCursor: CSSStyleDeclaration['cursor'];

/**
* Cursor value used for disabled elements ( corners with disabled action )
* @type String
* @since 2.0.0
* @default not-allowed
*/
notAllowedCursor: CSSStyleDeclaration['cursor'];
}

export interface TargetFindOptions {
/**
* When true, object detection happens on per-pixel basis rather than on per-bounding-box
* @type Boolean
* @default
*/
perPixelTargetFind: boolean;

/**
* Number of pixels around target pixel to tolerate (consider active) during object detection
* @type Number
* @default
*/
targetFindTolerance: number;

/**
* When true, target detection is skipped. Target detection will return always undefined.
* click selection won't work anymore, events will fire with no targets.
* if something is selected before setting it to true, it will be deselected at the first click.
* area selection will still work. check the `selection` property too.
* if you deactivate both, you should look into staticCanvas.
* @type Boolean
* @default
*/
skipTargetFind: boolean;
}

export interface CanvasEventsOptions {
/**
* Indicates if the right click on canvas can output the context menu or not
* @type Boolean
* @since 1.6.5
* @default
*/
stopContextMenu: boolean;

/**
* Indicates if the canvas can fire right click events
* @type Boolean
* @since 1.6.5
* @default
*/
fireRightClick: boolean;

/**
* Indicates if the canvas can fire middle click events
* @type Boolean
* @since 1.7.8
* @default
*/
fireMiddleClick: boolean;

/**
* When the option is enabled, PointerEvent is used instead of TPointerEvent.
* @type Boolean
* @default
*/
enablePointerEvents: boolean;
}

export interface CanvasOptions
extends StaticCanvasOptions,
CanvasTransformOptions,
CanvasSelectionOptions,
CanvasCursorOptions,
TargetFindOptions,
CanvasEventsOptions {
/**
* Default element class that's given to wrapper (div) element of canvas
* @type String
* @default
* @deprecated customize {@link CanvasDOMManager} instead or access {@link elements} directly
*/
containerClass: string;

/**
* Indicates whether objects should remain in current stack position when selected.
* When false objects are brought to top and rendered as part of the selection group
* @type Boolean
* @default
*/
preserveObjectStacking: boolean;
}

export const canvasDefaults: TOptions<CanvasOptions> = {
uniformScaling: true,
uniScaleKey: 'shiftKey',
centeredScaling: false,
centeredRotation: false,
centeredKey: 'altKey',
altActionKey: 'shiftKey',

selection: true,
selectionKey: 'shiftKey',
selectionColor: 'rgba(100, 100, 255, 0.3)',
selectionDashArray: [],
selectionBorderColor: 'rgba(255, 255, 255, 0.3)',
selectionLineWidth: 1,
selectionFullyContained: false,

hoverCursor: 'move',
moveCursor: 'move',
defaultCursor: 'default',
freeDrawingCursor: 'crosshair',
notAllowedCursor: 'not-allowed',

perPixelTargetFind: false,
targetFindTolerance: 0,
skipTargetFind: false,

stopContextMenu: false,
fireRightClick: false,
fireMiddleClick: false,
enablePointerEvents: false,

containerClass: 'canvas-container',

preserveObjectStacking: false,
};
Loading
Loading