Fabric.js copy-paste elements

Introduction to this article

Like + Follow + Collection = Learned

What do you consider when you copy an element of fabric? Deep copy the currently selected object and then add it to the canvas?

In fact, fabric.js provides a cloning method. There is also this demo in the case of fabric.js official website: Fabric.js demos · Copy and Paste.

This time I will talk about this demo.

file

Implementation Ideas

Before we get started, let’s clarify our thoughts.

  1. To copy elements, you must first have elements, so we create some elements on the page (seems like nonsense).
  2. Before copying, there must be a target to be copied. We can use the canvas.getActiveObject() method to get the currently selected element.
  3. When copying, you can use the clone() method to clone the currently selected element object.
  4. When pasting, use the canvas.add() method to add the cloned element to the canvas.

Of course, there are many small points that need to be paid attention to in actual development, such as how to copy and paste when selecting a group? How to copy and paste when selecting a bunch of elements?

These issues will be discussed later. Let’s first learn how to copy an element.

Hands-on coding

Once you understand the previous ideas, you can start!

Copy a single element

file

<div>
    <button οnclick="copy()">Copy</button>
    <button οnclick="paste()">Paste</button>
  </div>
  <canvas id="c" width="500" height="400" style="border: 1px solid #ccc;"></canvas>

<script src="//i2.wp.com/unpkg.com/[email protected]/dist/fabric.min.js"></script>
<script>
const canvas = new fabric.Canvas('c')

let rect = new fabric.Rect({
  left: 100,
  top: 50,
  fill: '#D81B60',
  width: 100,
  height: 100,
  strokeWidth: 2,
  stroke: '#880E4F',
  rx: 10,
  ry: 10,
  angle: 45
})

canvas.add(rect)

// Clone object
let _clipboard = null

// copy
function copy() {
  //The target element to be copied
  let target = canvas.getActiveObject()
  //Clone only when there is a selected element
  if (target) {
    target.clone(function(cloned) {
      _clipboard = cloned // Assign the cloned element to _clipboard
    })
  }
}

// Paste
function paste() {
  // If the cloned object does not exist, terminate the paste execution.
  if (!_clipboard) return

  //Perform the paste operation, clone the cloned object again, and then add it to the canvas.
  _clipboard.clone(function(clonedObj) {
    // appropriate displacement
    clonedObj.set({
      left: clonedObj.left + 10,
      top: clonedObj.top + 10,
      evented: true, // When set to "false", the object cannot be the target of an event. All events are propagated through it.
    })

    canvas.add(clonedObj) //Add the cloned element to the canvas

    // Modify the position of the cloned object so that it is easier to observe when pasting multiple times
    _clipboard.top + = 10
    _clipboard.left + = 10

    //Modify the currently selected item to the element newly cloned to the canvas
    canvas.setActiveObject(clonedObj)

    // Refresh the canvas
    canvas.requestRenderAll()
  })
}
</script>

First create 2 buttons and 1 canvas in the page, and create an element in the canvas.

In the JS section, you need to create a variable to save the cloned object. This variable is called _clipboard.

When performing a copy operation, it is necessary to determine whether the element object is currently selected.

When performing a paste operation, it is necessary to determine whether the element object is currently cloned.

replication group

In fact, copying a group is the same as copying a single element. It is also necessary to obtain the currently selected object. The group can be regarded as an element object.

The code is the same as above, just change the single element into a group. I quote the demo from the official website of fabric.js

file

//Omit some code

let circle1 = new fabric.Circle({
  radius: 65,
  fill: '#039BE5',
  left: 0
})

let circle2 = new fabric.Circle({
  radius: 65,
  fill: '#4FC3F7',
  left: 110,
  Opacity: 0.7
})

let group = new fabric.Group([circle1, circle2, ], {
  left: 40,
  top: 250
})

canvas.add(group)

Just add the previous copy and paste code.

Copy selected elements

The operation of copying box-selected elements will be relatively complicated, but it is only a matter of time.

file

Because more than one element is selected, all elements need to be traversed when pasting, using the forEachObject method provided by fabric.js.

//Omit some code

// Paste
function paste() {
  // If the cloned object does not exist, terminate the paste execution.
  if (!_clipboard) return

  _clipboard.clone(function(clonedObj) {
    // appropriate displacement
    clonedObj.set({
      left: clonedObj.left + 10,
      top: clonedObj.top + 10,
      evented: true
    })

    // Traverse and paste all selected elements
    clonedObj.canvas = canvas
    clonedObj.forEachObject(function(obj) {
      canvas.add(obj)
    })
    clonedObj.setCoords()

    // appropriate displacement
    _clipboard.top + = 10
    _clipboard.left + = 10

    // Select all newly pasted elements
    canvas.setActiveObject(clonedObj)
  })
}

The last thing that needs to be done is to be compatible with the selection of a single element or the selection of multiple elements.

After obtaining the currently selected object, there is a type attribute. When multiple elements are selected, the value of type will become activeSelection, and we will You can use this to determine whether a single element is currently selected or multiple elements are selected.

//Omit some code

// Paste
function paste() {
  // If the cloned object does not exist, terminate the paste execution.
  if (!_clipboard) return

  _clipboard.clone(function(clonedObj) {
    // appropriate displacement
    clonedObj.set({
      left: clonedObj.left + 10,
      top: clonedObj.top + 10,
      evented: true
    })

    if (clonedObj.type === 'activeSelection') {
      // Multiple elements are selected
      // Traverse and paste all selected elements
      clonedObj.canvas = canvas
      clonedObj.forEachObject(function(obj) {
        canvas.add(obj)
      })
      clonedObj.setCoords()
    } else {
      // Select an element
      canvas.add(clonedObj)
      _clipboard.top + = 10
      _clipboard.left + = 10
    }

    // appropriate displacement
    _clipboard.top + = 10
    _clipboard.left + = 10

    // Select all newly pasted elements
    canvas.setActiveObject(clonedObj)
    // Refresh the canvas
    canvas.requestRenderAll()
  })
}

In addition to the above mouse operations, we can also achieve the above effect by monitoring the keyboard’s ctrl + c and ctrl + v (mac monitoring command).

Leave this part of the work to the workers, I’ll leave first.

code warehouse

The complete code for this article can be obtained through the link below.

? Copy and paste elements

“Fabric.js from entry to _ _ _ _ _ _”

“Fabric.js dragging vertices to modify polygon shapes”

“Fabric.js explains the official demo: Stickman”

《Fabric.js Custom Control》

《What should I do if the Fabric.js style is not updated? 》

《Fabric.js Pattern Brush (Brush)》

Like + Follow + Collection = Learned Code Warehouse