1. Select multiple modules to combine and disgroup

1, combination

Composition is to combine selected modules into a group

Selected module:

card.getActiveObject()
Copy the code

Group:

// group and re-render
card.getActiveObject().toGroup()
card.renderAll()
Copy the code

2. Split and combine

// Get the selected combination module, split the combination and re-render
card.getActiveObject().toActiveSelection();
card.renderAll()
Copy the code

The left and top child elements are not correct

Problem: Loading SVG using loadSVGFromString results in incorrect left and top submodules after rendering

Reason: This is because the SVG loaded by loadSVGFromString is formed into a combination, and the child elements in the combination are left and top based on the base point of the combination, which is the center point, not the vertex position of our usual canvas

So you can combine them first and then split them

fabric.loadSVGFromString(svgContext, (objects) = > {
    // Group first
    const group1 = new fabric.Group(objects, {
        left: 0.top: 0
    })
    // Add the combination to card
    card.add(group1)
    // Set the combination to selected
    card.setActiveObject(group1)
    // Divide the selected group into groups
    card.getActiveObject().toActiveSelection();
    // Uncheck each separated module
    card.discardActiveObject()
    // re-render
    card.renderAll()
})
Copy the code

3. Load the Canvas canvas grid transparent background of fabric.js

Problem: The canvas needs to load the grid transparent background when initializing, so that the user can feel it as a transparent layer, so that they can operate on it

You can load a RECT of a custom type and fill the RECT with a 100 * 100 grid

Let’s say I have a 100 by 100 grid

// Initialize a rect, set width, height, left, top, custom type, and unselectable (most importantly, this background is not selectable)
const shapeBg = new fabric.Rect({
    width: card.width,
    height: card.height,
    left: 0.top: 0.fill: 'rgba(0, 0, 0, 0)'.myFabricType: 'bg'.selectable: false // Disable the check
})
card.add(shapeBg)
const url = 'Address of grid map'
// Load the grid diagram
fabric.util.loadImage(url, function(img) {
    // Fill the rect with images and set repeat to repeat
    shapeBg.set('fill'.new fabric.Pattern({
      source: img,
      repeat: 'repeat'
    }))
    / / rendering
    card.renderAll();
});
Copy the code

At this point card will render with a grid background

This recT must be loaded before rendering other modules. It is best to load this RECt when creating cards, otherwise there will be hierarchy problems

Write the blurred grid as an SVG and import it according to loadSVGFromString

Selectable: false is also required for imported SVG

Fabric.js loadSVGFromString Uncaught TypeError: Cannot set property ‘crossOrigin’ of undefined

In the fabric.js project, the SVG code generated by canvas.tosvg () is rendered by loadSVGFromString, causing an error

Error content

fabric.js:4477 Uncaught TypeError: Cannot set property 'crossOrigin' of undefined
    at Object.fabric.parseSVGDocument (fabric.js:4477)
    at Object.loadSVGFromString (fabric.js:4856)
    at testFabric4.html:225
Copy the code

Cause: The generated SVG content header introduces the HTTP: link. Change it to HTTPS:

svgContext = svgContext.replace(/http:\/\//g.'https://')
fabric.loadSVGFromString(svgContext, () = > {
    // ...  
})
Copy the code

Fabric.js reverses, restores, and saves each step

const state = {
    saveLen: 0.deleLen: 0.operIndex: -1
}
window.saveOperateList = []
window.deleteOperateList = []
const getters = {
    
}
const mutations = {
    // Manipulate the saved data
    OPERATE_OPERATE_DATA (state) {
        const json = window.card.toDatalessJSON()
        if (state.deleLen > 0) {
            window.deleteOperateList.some(item= > {
                window.saveOperateList[item].del = true
            })  
            window.saveOperateList = window.saveOperateList.filter(item= > {
                return! item.del })window.deleteOperateList = []
            window.saveOperateList.push(json)
            state.operIndex = window.saveOperateList.length - 1
        } else {
            window.saveOperateList.push(json)
            state.operIndex += 1
        }
        state.saveLen = window.saveOperateList.length
        state.deleLen = window.deleteOperateList.length
    },
    // Last step
    PREV_STEP_OPERATE (state) {
        if (state.operIndex > 0) {
            window.card.loadFromJSON(window.saveOperateList[state.operIndex - 1]).renderAll()
            if (window.deleteOperateList.includes(state.operIndex - 1)) {}else {
                window.deleteOperateList.push(state.operIndex)
                state.operIndex -= 1
            }
        }
        state.saveLen = window.saveOperateList.length
        state.deleLen = window.deleteOperateList.length
    },
    // Next step
    NEXT_STEP_OPERATE (state) {
        if (state.operIndex + 1> =window.saveOperateList.length) {
            return
        }
        window.card.loadFromJSON(window.saveOperateList[state.operIndex + 1]).renderAll()
        if (window.deleteOperateList.includes(state.operIndex + 1)) {
            const index = window.deleteOperateList.indexOf(state.operIndex + 1)
            window.deleteOperateList.splice(index, 1)}else {
        }
        state.operIndex = state.operIndex + 1
        state.saveLen = window.saveOperateList.length
        state.deleLen = window.deleteOperateList.length
    }
}
const actions = {
}
export default { state, getters, mutations, actions }
Copy the code

Field Description:

  • saveLen: Saves the data for each stepsaveOperateListThe length of the
  • deleLen: The data of each step needs to be deleteddeleteOperateListThe length of the
  • operIndex: Indicates the Index value of the operation
  • window.saveOperateList: Saved data. The saved value is the JSON data of each step
  • window.deleteOperateList: The data list to be deleted in each step is saved assaveOperateListEvery step of the wayindexThe value of the

Ideas:

  1. Save operation records:
    1. deleLen <= 0That is, no operation record needs to be deleted
      1. definejson:const json = window.card.toDatalessJSON()
      2. tosaveOperateListPush data in:window.saveOperateList.push(json)
      3. operIndexIncrement the value of:state.operIndex += 1
    2. deleLen > 0When, that is, there is data to delete operation records
      1. traversedeleteOperateListAn array,saveOperateList[item]Plus one for each objectdelProperty (value to be deleted)
      2. filter``saveOperateListArray, there aredelAttribute filtering
      3. deleteOperateListThe assignment for[]
      4. saveOperateListAdd new data
      5. Set up theoperIndexThe value of the
    3. Set up thesaveLen ε’Œ deleLenThe value of the
  2. Undo/Previous Step:
    1. ifoperIndex > 0
      1. Load last saved data:window.card.loadFromJSON(window.saveOperateList[state.operIndex - 1]).renderAll()
      2. ifdeleteOperateListContains the currentoperIndex - 1Do not enter any operation, otherwise theoperIndex push θΏ› deleteOperateListIn the
      3. Then put theoperIndex - 1
    2. ifoperIndex <= 0If no operation is performed, the undo (previous) operation cannot be performed
    3. Set up thesaveLen ε’Œ deleLenThe value of the
  3. Recovery/Next Steps:
    1. ifoperIndex + 1 > saveOperateList.lengthIf no operation is performed, the recovery cannot be performedreturnCan be
    2. loadingoperIndex + 1Data:window.card.loadFromJSON(window.saveOperateList[state.operIndex + 1]).renderAll()
    3. ifdeleteOperateListcontainsoperIndex + 1The value of fromdeleteOperateListDelete this value from; If it is not included, it is not deleted
    4. Set up theoperIndexThe value of the
    5. Set up thesaveLen ε’Œ deleLenThe value of the

At this point, a data saving, undo, restore the whole process is completed

Due to the setoperIndexIt’s minus 1, so it needs to becardSave initialization during initializationjsonData, called once after initialization is completeOPERATE_OPERATE_DATAfunction

Call OPERATE_OPERATE_DATA for each subsequent operation, PREV_STEP_OPERATE for each undo, and NEXT_STEP_OPERATE for each restore

Denver annual essay | 2020 technical way with me The campaign is under way…