Skip to content

Commit

Permalink
chore(TS): Migrate fabric.Collection (fabricjs#8433)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrea Bogazzi <andreabogazzi79@gmail.com>
  • Loading branch information
2 people authored and frankrousseau committed Jan 6, 2023
1 parent 9092cfb commit f748d9d
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 467 deletions.
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]

- chore(TS): migrate Collection [#8433](https://github.com/fabricjs/fabric.js/pull/8433)
- ci(): Simplify filestats even more [#8449](https://github.com/fabricjs/fabric.js/pull/8449)
- chore(TS): migrate filter backends [#8403](https://github.com/fabricjs/fabric.js/pull/8403)
- chore(TS): migrate Text classes/mixins [#8408](https://github.com/fabricjs/fabric.js/pull/8408)
Expand Down
5 changes: 2 additions & 3 deletions src/mixins/canvas_serialization.mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,10 @@
* @param {Array} enlivenedObjects canvas objects
*/
__setupCanvas: function (serialized, enlivenedObjects) {
var _this = this;
enlivenedObjects.forEach(function (obj, index) {
enlivenedObjects.forEach((obj, index) => {
// we splice the array just in case some custom classes restored from JSON
// will add more object to canvas at canvas init.
_this.insertAt(obj, index);
this.insertAt(index, obj);
});
// remove parts i cannot set as options
delete serialized.objects;
Expand Down
170 changes: 79 additions & 91 deletions src/mixins/collection.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,167 +1,155 @@
//@ts-nocheck
(function (global) {
var fabric = global.fabric;
/**
* @namespace fabric.Collection
*/
fabric.Collection = {
import { fabric } from '../../HEADER';
import type { FabricObject } from '../shapes/fabricObject.class';

export function createCollectionMixin(Klass: { new (...args: any[]): any }) {
return class Collection extends Klass {
/**
* @type {fabric.Object[]}
* @type {FabricObject[]}
*/
_objects: [],
_objects: FabricObject[] = [];

// eslint-disable-next-line @typescript-eslint/no-unused-vars
_onObjectAdded(object: FabricObject) {
// subclasses should override this method
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
_onObjectRemoved(object: FabricObject) {
// subclasses should override this method
}

/**
* Adds objects to collection, Canvas or Group, then renders canvas
* (if `renderOnAddRemove` is not `false`).
* Objects should be instances of (or inherit from) fabric.Object
* @private
* @param {fabric.Object[]} objects to add
* @param {(object:fabric.Object) => any} [callback]
* Adds objects to collection
* Objects should be instances of (or inherit from) FabricObject
* @param {...FabricObject[]} objects to add
* @returns {number} new array length
*/
add: function (objects, callback) {
var size = this._objects.push.apply(this._objects, objects);
if (callback) {
for (var i = 0; i < objects.length; i++) {
callback.call(this, objects[i]);
}
}
add(...objects: FabricObject[]) {
const size = this._objects.push(...objects);
objects.forEach((object) => this._onObjectAdded(object));
return size;
},
}

/**
* Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)
* An object should be an instance of (or inherit from) fabric.Object
* @private
* @param {fabric.Object|fabric.Object[]} objects Object(s) to insert
* @param {Number} index Index to insert object at
* @param {(object:fabric.Object) => any} [callback]
* Inserts an object into collection at specified index
* @param {number} index Index to insert object at
* @param {...FabricObject[]} objects Object(s) to insert
* @returns {number} new array length
*/
insertAt: function (objects, index, callback) {
var args = [index, 0].concat(objects);
this._objects.splice.apply(this._objects, args);
if (callback) {
for (var i = 2; i < args.length; i++) {
callback.call(this, args[i]);
}
}
insertAt(index: number, ...objects: FabricObject[]) {
this._objects.splice(index, 0, ...objects);
objects.forEach((object) => this._onObjectAdded(object));
return this._objects.length;
},
}

/**
* Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)
* @private
* @param {fabric.Object[]} objectsToRemove objects to remove
* @param {(object:fabric.Object) => any} [callback] function to call for each object removed
* @returns {fabric.Object[]} removed objects
* @param {...FabricObject[]} objects objects to remove
* @returns {FabricObject[]} removed objects
*/
remove: function (objectsToRemove, callback) {
var objects = this._objects,
removed = [];
for (var i = 0, object, index; i < objectsToRemove.length; i++) {
object = objectsToRemove[i];
index = objects.indexOf(object);
remove(...objects: FabricObject[]) {
const array = this._objects,
removed: FabricObject[] = [];
objects.forEach((object) => {
const index = array.indexOf(object);
// only call onObjectRemoved if an object was actually removed
if (index !== -1) {
objects.splice(index, 1);
array.splice(index, 1);
removed.push(object);
callback && callback.call(this, object);
this._onObjectRemoved(object);
}
}
});
return removed;
},
}

/**
* Executes given function for each object in this group
* A simple shortcut for getObjects().forEach, before es6 was more complicated,
* now is just a shortcut.
* @param {Function} callback
* Callback invoked with current object as first argument,
* index - as second and an array of all objects - as third.
* Callback is invoked in a context of Global Object (e.g. `window`)
* when no `context` argument is given
*
* @param {Object} context Context (aka thisObject)
* @return {Self} thisArg
* @chainable
*/
forEachObject: function (callback, context) {
var objects = this.getObjects();
for (var i = 0; i < objects.length; i++) {
callback.call(context, objects[i], i, objects);
}
return this;
},
forEachObject(
callback: (
object: FabricObject,
index: number,
array: FabricObject[]
) => any
) {
this.getObjects().forEach((object, index, objects) =>
callback(object, index, objects)
);
}

/**
* Returns an array of children objects of this instance
* @param {...String} [types] When specified, only objects of these types are returned
* @return {Array}
*/
getObjects: function () {
if (arguments.length === 0) {
return this._objects.concat();
getObjects(...types: string[]) {
if (types.length === 0) {
return [...this._objects];
}
var types = Array.from(arguments);
return this._objects.filter(function (o) {
return types.indexOf(o.type) > -1;
});
},
return this._objects.filter((o) => types.includes(o.type));
}

/**
* Returns object at specified index
* @param {Number} index
* @return {Object} object at index
*/
item: function (index) {
item(index: number) {
return this._objects[index];
},
}

/**
* Returns true if collection contains no objects
* @return {Boolean} true if collection is empty
*/
isEmpty: function () {
isEmpty() {
return this._objects.length === 0;
},
}

/**
* Returns a size of a collection (i.e: length of an array containing its objects)
* @return {Number} Collection size
*/
size: function () {
size() {
return this._objects.length;
},
}

/**
* Returns true if collection contains an object.\
* **Prefer using {@link `fabric.Object#isDescendantOf`} for performance reasons**
* **Prefer using {@link `FabricObject#isDescendantOf`} for performance reasons**
* instead of a.contains(b) use b.isDescendantOf(a)
* @param {Object} object Object to check against
* @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`
* @return {Boolean} `true` if collection contains an object
*/
contains: function (object, deep) {
if (this._objects.indexOf(object) > -1) {
contains(object: FabricObject, deep?: boolean): boolean {
if (this._objects.includes(object)) {
return true;
} else if (deep) {
return this._objects.some(function (obj) {
return (
typeof obj.contains === 'function' && obj.contains(object, true)
);
});
return this._objects.some(
(obj) => obj instanceof Collection && obj.contains(object, true)
);
}
return false;
},
}

/**
* Returns number representation of a collection complexity
* @return {Number} complexity
*/
complexity: function () {
return this._objects.reduce(function (memo, current) {
complexity() {
return this._objects.reduce((memo, current) => {
memo += current.complexity ? current.complexity() : 0;
return memo;
}, 0);
},
}
};
})(typeof exports !== 'undefined' ? exports : window);
}

fabric.createCollectionMixin = createCollectionMixin;
2 changes: 1 addition & 1 deletion src/mixins/object_ancestry.mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { FabricObject } from '../shapes/fabricObject.class';
/** @lends FabricObject.prototype */ {
/**
* Checks if object is decendant of target
* Should be used instead of @link {fabric.Collection.contains} for performance reasons
* Should be used instead of @link {Group.contains} or @link {StaticCanvas.contains} for performance reasons
* @param {fabric.Object|fabric.StaticCanvas} target
* @returns {boolean}
*/
Expand Down
Loading

0 comments on commit f748d9d

Please sign in to comment.