最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用fabric.js开发图片编辑器所遇到的问题合集一 | 掘金年度征文

    正文概述 掘金(日升)   2020-12-24   1104

    一、选中多个模块组合与拆分组

    1、组合

    组合是要把选中的模块组合成一个组

    选中的模块:

    card.getActiveObject()
    

    成组:

    // 成组 、重新渲染
    card.getActiveObject().toGroup()
    card.renderAll()
    

    2、拆分组合

    // 获取选中的组合模块,进行组合拆分、重新渲染
    card.getActiveObject().toActiveSelection();
    card.renderAll()
    

    二、loadSVGFromString 加载 SVG 导致子元素left和top值不对

    问题:通过 loadSVGFromString 加载 SVG ,渲染完成之后回导致 里面的子模块 lefttop 的值不正确

    原因:这个是因为,通过 loadSVGFromString 加载的 SVG 回被组成一个组合,组合里面的子元素按照组合的基点来算 lefttop 值,而组合的基点所在位置是中心点,不是我们通常的canvas的顶点位置

    所以可以先进行组合、在进行组合拆分

    fabric.loadSVGFromString(svgContext, (objects) => {
        // 先进行 组合成组
        const group1 = new fabric.Group(objects, {
            left: 0,
            top: 0
        })
        // 把组合 add 进 card
        card.add(group1)
        // 把组合设置为选中
        card.setActiveObject(group1)
        // 把选中的组合 进行拆分组
        card.getActiveObject().toActiveSelection();
        // 把拆分开的每一个模块进行取消选中状态
        card.discardActiveObject()
        // 重新渲染
        card.renderAll()
    })
    

    三、加载 fabric.js 的 canvas 虚化网格透明背景

    使用fabric.js开发图片编辑器所遇到的问题合集一 | 掘金年度征文

    问题:在 canvas 初始化时需要加载 网格透明背景,让用户感觉这个时一个透明的图层,从而可以在上面操作

    1、可以加载一个 rect,特定一个自定义类型,给这个 rect 填充一个 100 * 100 的网格图

    比如我有一个100*100的网格图

    使用fabric.js开发图片编辑器所遇到的问题合集一 | 掘金年度征文

    // 初始化一个 rect、设置宽、高、left、top、自定义类型、以及不可选中(最重要,这个背景不可选)
    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 // 禁止选中
    })
    card.add(shapeBg)
    const url = '网格图的地址'
    // 加载网格图
    fabric.util.loadImage(url, function(img) {
        // 对 rect 进行图片填充,设置 repeat 为 重复
        shapeBg.set('fill', new fabric.Pattern({
          source: img,
          repeat: 'repeat'
        }))
        // 渲染
        card.renderAll();
    });
    

    此时 card 渲染就会有一个网格的背景了

    这个rect一定要在渲染其他的模块之前进行加载,最好时创建card的时候就进行加载这个rect,不然的话会有层级的问题

    2、把这个虚化的网格写成一个 svg,根据 loadSVGFromString 进行导入

    导入的 svg 也是需要设置 selectable: false

    四、fabric.js loadSVGFromString Uncaught TypeError: Cannot set property 'crossOrigin' of undefined

    fabric.js 的项目中,使用 canvas.toSVG() 生成的 SVG 代码,在通过 loadSVGFromString 来进行渲染,报错

    错误内容

    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
    

    使用fabric.js开发图片编辑器所遇到的问题合集一 | 掘金年度征文

    原因:生成的 SVG 内容头部引入的 http: 链接,改成 https: 即可

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

    五、fabric.js 撤销、恢复和保存每一步操作

    const state = {
        saveLen: 0,
        deleLen: 0,
        operIndex: -1
    }
    window.saveOperateList = []
    window.deleteOperateList = []
    const getters = {
        
    }
    const mutations = {
        // 操作保存的数据
        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
        },
        // 上一步操作
        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_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 }
    

    字段解释:

    • saveLen:保存每一步的数据 saveOperateList 的长度
    • deleLen:需要删除每一步的数据 deleteOperateList 的长度
    • operIndex:操作的 Index 的值
    • window.saveOperateList:保存的数据,存的值为每一步的 json 数据
    • window.deleteOperateList:需要删除每一步的数据列表,存的值为 saveOperateList 的每一步的 index 的值

    思路:

    1. 保存操作记录:
      1. deleLen <= 0 即没有需要删除的操作记录
        1. 定义jsonconst json = window.card.toDatalessJSON()
        2. saveOperateList 中 push 数据:window.saveOperateList.push(json)
        3. operIndex的值往上加一:state.operIndex += 1
      2. deleLen > 0 的时候,即有删除操作记录的数据的时候
        1. 遍历deleteOperateList数组,给saveOperateList[item]每一个对象加一个del属性(需要删除掉的值)
        2. filter``saveOperateList数组,把有 del 属性的过滤掉
        3. deleteOperateList赋值为[]
        4. saveOperateList添加新的数据
        5. 设置 operIndex 的值
      3. 设置saveLendeleLen 的值
    2. 撤销/上一步操作:
      1. 如果operIndex > 0
        1. 加载上一次保存的数据:window.card.loadFromJSON(window.saveOperateList[state.operIndex - 1]).renderAll()
        2. 如果deleteOperateList包含当前operIndex - 1则不进任何操作,否则把operIndex pushdeleteOperateList
        3. 再把operIndex - 1
      2. 如果operIndex <= 0 不进行任何操作,说明此时不能进行撤销(上一步)操作
      3. 设置saveLendeleLen 的值
    3. 恢复/下一步操作:
      1. 如果operIndex + 1 > saveOperateList.length则不进行任何操作,说明此时不能进行恢复操作,直接return即可
      2. 加载 operIndex + 1 的数据:window.card.loadFromJSON(window.saveOperateList[state.operIndex + 1]).renderAll()
      3. 如果 deleteOperateList包含operIndex + 1的值,从deleteOperateList中删除这个值;如果不包含,则不删除
      4. 设置operIndex 的值
      5. 设置saveLendeleLen 的值

    此时即完成了一个 保存数据、撤销、恢复整个流程

    由于设置的 operIndex 为 -1 ,所以需要在 card 初始化时进行保存初始化的 json 数据,在初始化完成之后进行调用一次 OPERATE_OPERATE_DATA函数

    后面每次进行操作的时候调用 OPERATE_OPERATE_DATA,每次点击撤销的时候调用PREV_STEP_OPERATE,点击恢复的时候调用NEXT_STEP_OPERATE

    掘金年度征文 | 2020 与我的技术之路 征文活动正在进行中......


    起源地下载网 » 使用fabric.js开发图片编辑器所遇到的问题合集一 | 掘金年度征文

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    https://github.com/nihaojob/vue-fabric-editor 基于vue和fabric开发的图片编辑器
    回复(0)

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元