使用fabricjs从json到图像

Posted

技术标签:

【中文标题】使用fabricjs从json到图像【英文标题】:From json to image using fabricjs 【发布时间】:2020-02-26 08:12:49 【问题描述】:

我将一个 fabricjs 画布作为 json 保存在我的数据库中。我无意修改它,我只是想恢复它,调整它的大小,最后创建一个 PNG 或 JPG 图像,我将添加到我的网页中。

到目前为止,我已经完成了以下工作:

我创建了一个 canvas html 元素并将其隐藏 我在它上面加载了 de json(这个工作) 从那个画布中,我获得了它的上下文,我调整了它的大小,我得到了 dataURL(我得到了一个明显好的 url) 我创建了一个 html 元素并将 dataURL 与 img src 匹配

它似乎工作,但图像是透明的。大小还可以,但里面什么都没有。 我想这样做而不必创建画布元素并隐藏它。 例如,在 js 脚本上创建一个 var,在其上加载 json,调整其大小,获取 dataurl 并将其设置在元素上。

var exerciseList;

var canvas0 = new fabric.Canvas('canvas0');
var canvas1 = new fabric.Canvas('canvas1');
var canvas2 = new fabric.Canvas('canvas2');
var canvas3 = new fabric.Canvas('canvas3');
var canvas4 = new fabric.Canvas('canvas4');

$(document).ready(function () 
    var login = $.session.get("login");

    $.ajax(
        url: backEndpoint + "usuarios/" + login + "/ejercicios",
        headers: 
            "Content-Type": "application/json"
        ,
        method: "GET"
    )
        .done(function (data, textStatus, xhr) 
            exerciseList = data;
            for (var i = 0; i < exerciseList.length; i++) 
                addExercise(exerciseList[i],i);
                loadExercise(exerciseList[i],i);
            

        )
        .fail(function (xhr, textStatus, errorThrown) 


        );
);
var canvas;

function loadExercise(exercise, idx) 
    switch (idx) 
        case 0:
            canvas = canvas0;
            break;
        case 1:
            canvas = canvas1;
            break;
        case 2:
            canvas = canvas2;
            break;
        case 3:
            canvas = canvas3;
            break;
        case 4:
            canvas = canvas4;
            break;
        default:
            console.log("ERROR")
            break;
    
    canvas.loadFromJSON(exercise.figura, callbackFunction(idx));


function callbackFunction(idx) 
    canvas.renderAll.bind(canvas);
    //canvas.requestRenderAll(); // It doesnt work with anyone
    var $img = getImage(idx);
    $("#imageContainer"+idx).append($img);


function getImage(idx) 

    var width = 343;
    var height = 300;

    var resizedCanvas = document.createElement("canvas");
    var resizedContext = resizedCanvas.getContext("2d");

    resizedCanvas.width = "" + width;
    resizedCanvas.height = "" + height;

    var canvas = document.getElementById("canvas"+idx);

    resizedContext.drawImage(canvas, 0, 0, width, height);
    var myResizedData = resizedCanvas.toDataURL();

    return $('<img>').attr("src", myResizedData);



function addExercise(exercise, idx) 
    var title = exercise.titulo;
    var description = exercise.descripcion;

    var $exerciseContainer = $('<div>',
         id: "exerciseContainer"+idx,class: "row ejercicio m-1 rounded border border-secondary" );

    var $imageContainer = $('<div>',
         id: "imageContainer"+idx, class: "col-7 p-1 border border-secondary" );

    var $bodyContainer = $('<div>',
         id: "bodyContainer"+idx, class: "col border border-secondary" );

    $('<div>',  class: "row h4 p-1" ).text(title).appendTo($bodyContainer);
    $('<div>',  class: "row  p-1" ).text(resumirDescripcion(description)).appendTo($bodyContainer);

    var $buttonContainer = $('<div>',
         id: "buttonContainer"+idx, class: "col-1  p-1 border border-secondary" );

    $('<button>',  class: "btn btn-success btn-block p-2" ).appendTo($buttonContainer);
    $('<button>',  class: "btn btn-primary btn-block p-2" ).appendTo($buttonContainer);
    $('<button>',  class: "btn btn-warning btn-block p-2" ).appendTo($buttonContainer);
    $('<button>',  class: "btn btn-info btn-block p-2" ).appendTo($buttonContainer);
    $('<button>',  class: "btn btn-danger btn-block p-2" ).appendTo($buttonContainer);

    $exerciseContainer.append($imageContainer);
    $exerciseContainer.append($bodyContainer);
    $exerciseContainer.append($buttonContainer);

    $("#contenedorEjercicios").append($exerciseContainer);

我不知道为什么,但是当我按下一个按钮时调用这个函数它应该可以正常工作,但是我需要它在页面加载时工作。

this is what I get when the page loads

this is what I want to get

重构部分代码后得到this,但还是和之前一样。

【问题讨论】:

您可能正试图在图像渲染之前在调整大小的画布上绘制隐藏的画布。你什么时候打电话给appendImage() 我调用了一个ajax函数从数据库中获取数据,然后我调用functionA()。在functionA() 中,我首先执行loadFromJSON(),然后在下面的几行中,我调用appendImage() 能否将相关代码添加到您的问题中? 当然,给我几分钟 这些是我的功能 【参考方案1】:
canvas.loadFromJSON(canvasJSON, function()
  var url = canvas.toDataURL();
  var $img = getImage();
  $imageContainer.append($img);
);

canvas#loadFromJSON 对于某些对象是异步的,所以最好在loadFromJSON 的回调中创建图像。

canvas.loadFromJSON(exercise.figura, callbackFunction(idx)); 在这一行中这样做会callbackFunction(idx) 执行callbackFunction

如果您想将匿名函数更改为命名函数并且需要传递参数,您可以这样做。


canvas.loadFromJSON(json, () => callbackFunction(exercise,idx))
function callbackFunction(exercise, idx)
  canvas.requestRenderAll();
  var url = canvas.toDataURL();
  var $img = getImage(idx);
  $imageContainer.append($img);
;

【讨论】:

我也认为异步是这里的关键,但据我所知,您的代码不起作用; getImage() 预计 canvas.renderAll 已经发生。 啊,好吧,我没用过fabricjs。 @ChrisG,只是为了确认,确实重新检查了,内部它调用了renderAll(),虽然我添加了requestRenderAll(),如果不是,那么在回调时它会再次呈现。 我已经尝试了你的建议。我已经更新了代码,但它仍然没有工作@Durga @rubengonzalez96 调用了 renderAll,你能再检查一下吗?【参考方案2】:

我有一个半解决方案,我知道这不是最佳做法,但它允许我继续该项目。代码和我在问题中写的一样,但我改变了这个:

function callbackFunction(idx) 
   canvas.renderAll.bind(canvas)();
   setTimeout(function () 
       var $img = getImage(idx);
       $("#imageContainer" + idx).append($img);
   , 500);

画布渲染只需强制等待半秒...

【讨论】:

以上是关于使用fabricjs从json到图像的主要内容,如果未能解决你的问题,请参考以下文章

从画布中删除图像-fabricjs(javascript)

FabricJS:使用 Image 子类时无法执行“drawImage”

如何从 JSON 重新加载自定义 fabricJS 画布对象?

是否可以使用fabricjs以英寸为单位获取文本或图像对象的大小?

将图像拖放到画布(FabricJS)

使用 FabricJs 的裁剪功能