Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom drawing tool with custom properties in Fabric Js

Tags:

fabricjs

i am trying to create a custom drawing tool in the context of Fabric Js. By custom i mean to apply to every drawn free line custom properties e.g.:
1) - id of the created object;
2) - who created it;
3) - when is created
4) - when is updated
5)- etc.


For some other elements in the canvas that was more easy, e.g. for Circle, Rectangle, Triangle
Example (typescript, Angular code):

export class Circle extends fabric.Circle implements ExtendedFabricOptions {
id: string;
createdBy: string;
editedBy: string;
createdOn: string;
updatedOn: string;

constructor(props: ICircleOptions) {
    super(props);
    this.id = props.id;
    this.createdBy = props.createdBy;
    this.editedBy = props.editedBy;
    this.createdOn = props.createdOn;
    this.updatedOn = props.updatedOn;
}
}


And implementation of the code:
onMouseDown(e: fabric.IEvent) {
const mousedownPointer: fabric.ICoords2d = {
  x: e.pointer.x,
  y: e.pointer.y
};

const object: Circle = new Circle({
  radius: 1,
  fill: this.fillColor,
  stroke: this.strokeColor,
  strokeWidth: this.strokeThickness,
  left: e.pointer.x,
  top: e.pointer.y,
  includeDefaultValues: false,
  id: this.whiteboardService.generateUUID(),
  createdBy: this.attendeeId,
  createdOn: (new Date()).getTime()
});


onMouseMove(e: fabric.IEvent, mousedownPointer: fabric.ICoords2d, object: Circle) {
    ... update Circle object here
}


onMouseUp(e: fabric.IEvent, object: Circle) {
    ... final logic here
}


But for Brush and Pencil is more complicated, since after setting the "isDrawingMode" property of the canvas (this.canvas.isDrawingMode = true;) to "true" we have already creating an object, which behind the scene Fabric is attaching mousedown, mousemove, and mouseup event handlers. On mouseup "'mouseup' event, Fabric fires 'path:created' event and actually transforms just-drawn shape into a real fabric.Path instance!"
So, based on this information - which would be the best approach to draw customized brushes with custom properties (id, creatdOn, UpdatedBy... etc...). From which object is good my custom object to extend: For example:
export class Highlighter extends fabric.BaseBrush implements ExtendedFabricOptions {
  uuid: string;
  createdBy: string;

  constructor() {
    ...
  }
}

OR:

export class Highlighter extends fabric.Path implements ExtendedFabricOptions

And based on extending the object, what will be the best way to create it: If path there might be events for mousedown, mousemove and mouseup handling and updating the newly created instance of that Class.

Thank you in advance. That is very important topic since there are a lot of people trying to that the same behavior in the the most proper way!


Based on the answer for overriding mouse events of the freeDrawingBrush and including this.createdBy = 'some user id' and including other custom properties. In fact these properties are applied to the class but not to the created instance. The goal is every created brush object, on selection to hold it's own properties (it's own id, creator id, etc...) With provided answer "this" in the mouse handler is:
enter image description here

But on selection the same element doesn't have these properties:
enter image description here

like image 436
Virto111 Avatar asked Oct 09 '18 11:10

Virto111


1 Answers

Override mouse handlers of freeDrawingBrush. You need to define the same if you are changing canvas.freeDrawingBrush.

var canvas = new fabric.Canvas('c');
canvas.freeDrawingBrush = new fabric.CircleBrush(canvas)
canvas.isDrawingMode = 'true';
var pathId = 0;

canvas.freeDrawingBrush.onMouseDown = (function(onMouseDown) {
  return function(pointer) {
    console.log('down');
    this.createdOn = Date.now();
    onMouseDown.call(this, pointer);
  }
})(canvas.freeDrawingBrush.onMouseDown);

canvas.freeDrawingBrush.onMouseMove = (function(onMouseMove) {
  return function(pointer) {
    onMouseMove.call(this, pointer);
  }
})(canvas.freeDrawingBrush.onMouseMove);

canvas.freeDrawingBrush.onMouseUp = (function(onMouseUp) {
  return function(pointer) {
    console.log('up');
    this.updatedOn = Date.now();
    onMouseUp.call(this, pointer);
  }
})(canvas.freeDrawingBrush.onMouseUp);

canvas.on('path:created',function({path}){
  path.createdOn = canvas.freeDrawingBrush.createdOn;
  path.updatedOn = canvas.freeDrawingBrush.updatedOn;
  path.pathId = pathId++;
  console.log(path.createdOn)
  console.log(path.updatedOn)
});
function onSelect(){
  canvas.isDrawingMode = false;
  canvas.selection = true;
}
function onDrawing(){
  canvas.isDrawingMode = true;
  canvas.selection = false;
}
canvas.on('object:selected',function(options){
console.log(options.target)
})
canvas{
  border:1px solid;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<button onClick='onSelect()'>select</button>
<button onClick='onDrawing()'>drawing</button>
<canvas id='c' width=300 height=300>
like image 68
Durga Avatar answered Nov 13 '22 03:11

Durga