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

feat(): DrawShape, DrawOval, DrawPoly #8430

Open
wants to merge 84 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
653946c
svg
ShaMan123 Oct 31, 2022
b371499
SHARED_ATTRIBUTES
ShaMan123 Oct 31, 2022
a71cfc2
migrate
ShaMan123 Oct 31, 2022
e169232
Update circle.class.ts
ShaMan123 Oct 31, 2022
b0d0379
Update circle.class.ts
ShaMan123 Oct 31, 2022
4e7e498
defaults
ShaMan123 Oct 31, 2022
403d791
static
ShaMan123 Oct 31, 2022
575af88
Update CHANGELOG.md
ShaMan123 Oct 31, 2022
8f64f77
init
ShaMan123 Oct 31, 2022
ec4ac19
more
ShaMan123 Oct 31, 2022
1c21ea1
m
ShaMan123 Nov 1, 2022
4ba47fa
poly
ShaMan123 Nov 1, 2022
c66798c
Update polyline.class.ts
ShaMan123 Nov 1, 2022
63442ff
more
ShaMan123 Nov 1, 2022
fd2afa6
unpleasant
ShaMan123 Nov 1, 2022
4b6cc54
imports
ShaMan123 Nov 1, 2022
9acdd8d
Merge branch 'master' into ts-poly
ShaMan123 Nov 1, 2022
535fee0
Update CHANGELOG.md
ShaMan123 Nov 1, 2022
de8b311
more
ShaMan123 Nov 1, 2022
66a14cc
revert Point
ShaMan123 Nov 1, 2022
65cfcd6
IPoint
ShaMan123 Nov 1, 2022
5681fce
refactor `fromElementGenerator` => `polyFromElement`
ShaMan123 Nov 1, 2022
1d18a15
Update polyline.class.ts
ShaMan123 Nov 1, 2022
ce8660d
Update polyline.class.ts
ShaMan123 Nov 1, 2022
f6eb764
remove default points
ShaMan123 Nov 1, 2022
b5b5126
abstract methods + tidyup
ShaMan123 Nov 7, 2022
c536ecb
Update base_brush.class.ts
ShaMan123 Nov 7, 2022
faf374e
Update CHANGELOG.md
ShaMan123 Nov 7, 2022
2558035
Update base_brush.class.ts
ShaMan123 Nov 7, 2022
7576a6a
feat(): PolyBrush
ShaMan123 Nov 7, 2022
6826935
Update PolyBrush.ts
ShaMan123 Nov 7, 2022
ef485d5
Update PolyBrush.ts
ShaMan123 Nov 7, 2022
63762e8
Merge branch 'master' into ts-poly
ShaMan123 Nov 7, 2022
8f9d9d6
Merge branch 'ts-poly' into poly-brush2
ShaMan123 Nov 7, 2022
5e1f1fd
feat(): ShapeBrush
ShaMan123 Nov 7, 2022
a195dc5
shape brush
ShaMan123 Nov 7, 2022
11790a3
Merge branch 'brushes-patch' into poly-brush2
ShaMan123 Nov 7, 2022
653ddbb
Update base_brush.class.ts
ShaMan123 Nov 7, 2022
be2e508
Update ShapeBrush.ts
ShaMan123 Nov 7, 2022
3e8d0f6
Update ellipse.class.ts
ShaMan123 Nov 7, 2022
b8f308e
Update ShapeBrush.ts
ShaMan123 Nov 7, 2022
2c78623
circular shape brush
ShaMan123 Nov 7, 2022
5073ee7
symmetric
ShaMan123 Nov 7, 2022
f3dece5
refactor
ShaMan123 Nov 7, 2022
4580f41
Update ShapeBaseBrush.ts
ShaMan123 Nov 7, 2022
6ae1ea3
rename
ShaMan123 Nov 7, 2022
942cf90
Update DrawShapeBase.ts
ShaMan123 Nov 7, 2022
3bd0685
Update DrawShapeBase.ts
ShaMan123 Nov 7, 2022
62541fd
Update DrawShapeBase.ts
ShaMan123 Nov 7, 2022
a936296
Merge branch 'master' into poly-brush2
ShaMan123 Nov 21, 2022
4c28bbe
fix use `setBoundingBox`
ShaMan123 Nov 22, 2022
31cae7f
Create draw_shapes.js
ShaMan123 Nov 22, 2022
39bb29f
extensive tests!
ShaMan123 Nov 22, 2022
1e1db9a
expose super class method `transform`
ShaMan123 Nov 23, 2022
6062754
shadow
ShaMan123 Nov 23, 2022
70c9e0f
Merge branch 'master' into poly-brush2
ShaMan123 Nov 27, 2022
4ab566d
Update CHANGELOG.md
ShaMan123 Nov 27, 2022
03e4150
imports
ShaMan123 Nov 27, 2022
6d182e0
fix merge artifact
ShaMan123 Nov 27, 2022
c267640
Update DrawShapeBase.ts
ShaMan123 Nov 27, 2022
211bfe7
imports/types
ShaMan123 Nov 27, 2022
0d9a685
Merge branch 'master' into poly-brush2
ShaMan123 Nov 29, 2022
2e9d441
Merge branch 'master' into poly-brush2
ShaMan123 Dec 4, 2022
f23de4f
Merge branch 'master' into poly-brush2
ShaMan123 Dec 6, 2022
1e41df3
Merge branch 'master' into poly-brush2
ShaMan123 Dec 9, 2022
a2403c0
Merge branch 'master' into poly-brush2
ShaMan123 Dec 11, 2022
a3bb345
Merge branch 'master' into poly-brush2
ShaMan123 Dec 12, 2022
f49bd78
Merge branch 'master' into poly-brush2
ShaMan123 Dec 25, 2022
cafd0b3
fix(): imports after updating from master
ShaMan123 Dec 25, 2022
0c47f6a
Merge branch 'master' into poly-brush2
ShaMan123 Dec 29, 2022
f53a921
fix merge conflict
ShaMan123 Dec 29, 2022
bae043b
Update CHANGELOG.md
ShaMan123 Dec 29, 2022
c6f5896
Update base_brush.class.ts
ShaMan123 Dec 29, 2022
ea3c88b
Update DrawShapeBase.ts
ShaMan123 Dec 29, 2022
62e94e5
Update canvas.class.ts
ShaMan123 Dec 29, 2022
d59f41d
better types
ShaMan123 Dec 30, 2022
94c4a9e
forgotten
ShaMan123 Dec 30, 2022
81a92fe
Merge branch 'master' into poly-brush2
ShaMan123 Jan 6, 2023
9093607
export
ShaMan123 Jan 6, 2023
e5dc0d2
cleanup
ShaMan123 Jan 6, 2023
63af835
Merge branch 'master' into poly-brush2
ShaMan123 Feb 4, 2023
d790f4b
Update CHANGELOG.md
ShaMan123 Feb 4, 2023
8c0a447
fix imports, merge error
ShaMan123 Feb 4, 2023
2b86cde
Merge branch 'master' into poly-brush2
ShaMan123 Feb 5, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- feat(): DrawShape, DrawOval, DrawPoly [#8430](https://github.com/fabricjs/fabric.js/pull/8430)
- patch(): Added WebGLProbe to env, removed isLikelyNode, added specific env dispose ( instead of cleanup JSDOM ) [#8652](https://github.com/fabricjs/fabric.js/pull/8652)
- ci(): Removed the browser publish script [#8656](https://github.com/fabricjs/fabric.js/pull/8656)
- feat(): Node entry point [#8632](https://github.com/fabricjs/fabric.js/pull/8632)
Expand Down
8 changes: 8 additions & 0 deletions fabric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ 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 { DrawOval } from './src/brushes/DrawOval';
import { DrawPoly } from './src/brushes/DrawPoly';
import { DrawShape } from './src/brushes/DrawShape';
import { DrawShapeBase } from './src/brushes/DrawShapeBase';
import { FabricObject as Object } from './src/shapes/Object/FabricObject';
import { Line } from './src/shapes/Line';
import { Circle } from './src/shapes/Circle';
Expand Down Expand Up @@ -394,6 +398,10 @@ export {
CircleBrush,
SprayBrush,
PatternBrush,
DrawOval,
DrawPoly,
DrawShape,
DrawShapeBase,
Object,
Line,
Circle,
Expand Down
15 changes: 10 additions & 5 deletions src/brushes/BaseBrush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { TEvent } from '../EventTypeDefs';
import type { Shadow } from '../Shadow';
import type { Canvas } from '../canvas/Canvas';

type TBrushEventData = TEvent & { pointer: Point };
export type TBrushEventData = TEvent & { pointer: Point };

/**
* @see {@link http://fabricjs.com/freedrawing|Freedrawing demo}
Expand Down Expand Up @@ -85,6 +85,10 @@ export abstract class BaseBrush {
* @returns true if brush should continue blocking interaction
*/
abstract onMouseUp(ev: TBrushEventData): boolean | void;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
onDoubleClick(pointer: Point) {
// noop
}

/**
* Sets brush styles
Expand All @@ -100,15 +104,16 @@ export abstract class BaseBrush {
ctx.setLineDash(this.strokeDashArray || []);
}

transform(ctx: CanvasRenderingContext2D) {
ctx.transform(...this.canvas.viewportTransform);
}

/**
* Sets the transformation on given context
* @param {CanvasRenderingContext2D} ctx context to render on
* @private
*/
protected _saveAndTransform(ctx: CanvasRenderingContext2D) {
const v = this.canvas.viewportTransform;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
this.transform(ctx);
}

protected needsFullRender() {
Expand Down
34 changes: 34 additions & 0 deletions src/brushes/DrawOval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Point } from '../Point';
import { Ellipse } from '../shapes/Ellipse';
import { DrawShape } from './DrawShape';

export class DrawOval extends DrawShape<Ellipse> {
builder = Ellipse;

protected setBounds(a: Point, b: Point) {
const v = b.subtract(a);
const shape = this.shape!;
const d = new Point(Math.abs(v.x), Math.abs(v.y));
// set radii
if (this.symmetric) {
const r = this.centered
? d.distanceFrom(new Point())
: Math.max(d.x, d.y) / 2;
shape.set({ rx: r, ry: r });
} else {
const { x: rx, y: ry } = this.centered ? d : d.scalarDivide(2);
shape.set({ rx, ry });
}
// set position
if (this.centered) {
shape.setPositionByOrigin(a, 0.5, 0.5);
} else {
// keep a in place
shape.setPositionByOrigin(
a,
-Math.sign(v.x) * 0.5 + 0.5,
-Math.sign(v.y) * 0.5 + 0.5
);
}
}
}
61 changes: 61 additions & 0 deletions src/brushes/DrawPoly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Point } from '../Point';
import { Polygon } from '../shapes/Polygon';
import { Polyline } from '../shapes/Polyline';
import { DrawShapeBase } from './DrawShapeBase';

export class DrawPoly extends DrawShapeBase<Polyline> {
builder = Polygon;

private addPoint(pointer: Point) {
this.shape!.points.push(pointer);
}

private replacePoint(pointer: Point) {
this.shape!.points.pop();
this.addPoint(pointer);
this._render();
}

create() {
return new this.builder();
}

protected finalize() {
// release interaction
this.canvas._isCurrentlyDrawing = false;
const shape = this.shape;
if (!shape) return;
shape.setBoundingBox(true);
const r = this.width / 2;
shape.set({
left: shape.left + r,
top: shape.top + r,
});
super.finalize();
}

onMouseDown(pointer: Point) {
if (this.shape) {
this.addPoint(pointer);
} else {
this.build();
this.addPoint(pointer);
this.addPoint(pointer);
}
}

onMouseMove(pointer: Point) {
this.replacePoint(pointer);
}

onMouseUp({ pointer }: { pointer: Point }) {
this.replacePoint(pointer);
this.addPoint(pointer);
return true;
}

onDoubleClick(pointer: Point) {
this.shape && this.replacePoint(pointer);
this.finalize();
}
}
76 changes: 76 additions & 0 deletions src/brushes/DrawShape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ModifierKey } from '../EventTypeDefs';
import { Point } from '../Point';
import type { FabricObject } from '../shapes/Object/FabricObject';
import { Rect } from '../shapes/Rect';
import { Constructor } from '../typedefs';
import { TBrushEventData } from './BaseBrush';
import { DrawShapeBase } from './DrawShapeBase';

export class DrawShape<T extends FabricObject = Rect> extends DrawShapeBase<T> {
/**
* class to build shape from
*/
builder: Constructor<T> = Rect as unknown as Constructor<T>;

/**
* set to `true` for the shape to be centered on mouse/touch down
*/
centered = false;

/**
* The event modifier key that makes the brush symmetric.
*/
modifierKey?: ModifierKey = 'shiftKey';

/**
* set to `true` for the shape to be symmetric
*/
symmetric?: boolean;

protected start: Point;

create() {
return new this.builder();
}

protected setBounds(a: Point, b: Point) {
const v = b.subtract(a);
const shape = this.shape!;
const d = new Point(Math.abs(v.x), Math.abs(v.y));
// size
if (this.symmetric) {
const side =
(d.distanceFrom(new Point()) / Math.SQRT2) * (this.centered ? 2 : 1);
shape.set({ width: side, height: side });
} else {
shape.set({ width: d.x, height: d.y });
}
// position
if (this.centered) {
shape.setPositionByOrigin(a, 0.5, 0.5);
} else {
// keep a in place
shape.setPositionByOrigin(
a,
-Math.sign(v.x) * 0.5 + 0.5,
-Math.sign(v.y) * 0.5 + 0.5
);
}
}

onMouseDown(pointer: Point) {
this.build();
this.start = pointer;
}

onMouseMove(pointer: Point, ev: TBrushEventData) {
this.symmetric = this.modifierKey && ev.e[this.modifierKey];
this.setBounds(this.start, pointer);
this._render();
}

onMouseUp(ev: TBrushEventData) {
this.setBounds(this.start, ev.pointer);
this.finalize();
}
}
64 changes: 64 additions & 0 deletions src/brushes/DrawShapeBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Point } from '../Point';
import { Shadow } from '../Shadow';
import type { FabricObject } from '../shapes/Object/FabricObject';
import { BaseBrush } from './BaseBrush';

/**
* Declarative shape drawing using pointer events
*/
export abstract class DrawShapeBase<T extends FabricObject> extends BaseBrush {
shape: T | undefined;
stroke = '';
fill = '';

abstract create(): T;

protected build() {
this.shape = this.create();
this.shape.set('canvas', this.canvas);
this.setStyles();
}

setStyles() {
this.shape?.set({
stroke: this.stroke || this.color,
fill: this.fill || this.color,
strokeWidth: this.width,
strokeLineCap: this.strokeLineCap,
strokeMiterLimit: this.strokeMiterLimit,
strokeLineJoin: this.strokeLineJoin,
strokeDashArray: this.strokeDashArray,
shadow: this.shadow ? new Shadow(this.shadow) : undefined,
});
}

protected finalize() {
const shape = this.shape;
if (!shape) return;
shape.setCoords();
this.canvas.fire('before:path:created', { path: shape });
this.canvas.add(shape);
this.canvas.fire('path:created', { path: shape });
this.canvas.clearContext(this.canvas.contextTop);
this.shape = undefined;
}

_setBrushStyles() {
this.setStyles();
}

transform(ctx: CanvasRenderingContext2D) {
const t = this.canvas.viewportTransform;
const offset = new Point().transform(t);
ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y);
}

_render(ctx: CanvasRenderingContext2D = this.canvas.contextTop) {
this.canvas.clearContext(ctx);
ctx.save();
this.transform(ctx);
this.shape!.transform(ctx);
this.shape!._render(ctx);
ctx.restore();
}
}
9 changes: 1 addition & 8 deletions src/canvas/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,10 +539,6 @@ export class Canvas extends SelectableCanvas {
this.fire('drop:after', options);
}

/**
* @private
* @param {Event} e Event object fired on mousedown
*/
private _onContextMenu(e: TPointerEvent): false {
const target = this.findTarget(e),
subTargets = this.targets || [];
Expand All @@ -557,11 +553,8 @@ export class Canvas extends SelectableCanvas {
return false;
}

/**
* @private
* @param {Event} e Event object fired on mousedown
*/
private _onDoubleClick(e: TPointerEvent) {
this.freeDrawingBrush?.onDoubleClick(this.getPointer(e));
this._cacheTransformEventData(e);
this._handleEvent(e, 'dblclick');
this._resetTransformEventData();
Expand Down
2 changes: 1 addition & 1 deletion src/shapes/Ellipse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class Ellipse extends FabricObject {
* @param {Object} [options] Options object
* @return {Ellipse} thisArg
*/
constructor(options: Record<string, unknown>) {
constructor(options?: Record<string, unknown>) {
super(options);
}

Expand Down
2 changes: 1 addition & 1 deletion src/shapes/Rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class Rect extends FabricObject {
* @param {Object} [options] Options object
* @return {Object} thisArg
*/
constructor(options: Record<string, unknown>) {
constructor(options?: Record<string, unknown>) {
super(options);
this._initRxRy();
}
Expand Down
Loading