Fabric.js 对象在 DOM 加载时从 JSON 呈现时无法更改填充颜色

Posted

技术标签:

【中文标题】Fabric.js 对象在 DOM 加载时从 JSON 呈现时无法更改填充颜色【英文标题】:Fabric.js object fails to change fill color when rendered from a JSON at the time the DOM loads 【发布时间】:2021-10-24 07:15:02 【问题描述】:

我正在尝试采用 Fabric.js 风格化的画布元素,将其转换为 JSON,然后在具有较低权限的用户可以访问的页面上呈现有限/略微静态的 Canvas 版本。当呈现此用户版本的表单时,我在 DOM 加载时使用 JQuery 调用 canvas.loadFromJSON() 方法,并在回调函数中对对象进行一些验证/编辑(即填充颜色、hasControls、可选择等)。但是,这些更改中只有一些生效,其中一个我在成为颜色时遇到了麻烦。有趣的是,当我 console.log 对象并查看填充属性时,它发生了变化。这只是它的实际视觉效果。

这里是代码...

let canvas = new fabric.Canvas("leasables-configuration");
// arrays that store different entities up for lease based on their status
//I need each of the elements in these to be different colors
let leasables = []; 
let closed = [];
let available = [];
let leased = [];

//use JQuery to run async requests so that I can 
//sort the various entities up for lease

$(function()
    fetch("/api/leasables/get-all",method: 'GET')
        .then(response =>response.json())
        .then(data => console.log(data);
                for (let leasable in data) 
                    leasables.push(data[leasable])
                    switch (data[leasable].leasableStatus.leasableStatus) 
                        case "leased":
                            console.log(data[leasable].leasableCode);
                            leased.push(data[leasable].leasableCode);
                            break;
                        case "open":
                            console.log(data[leasable].leasableCode);
                            available.push(data[leasable].leasableCode);
                            break;
                        case "closed":
                            console.log(data[leasable].leasableCode);
                            closed.push(data[leasable].leasableCode);
                            break;
                        default: break;
                    ;
                
//Start second async request to fetch JSON string from my POJO that is currently //published
                return fetch("/api/configurations/load", method: 'GET')
            ).then(response => response.json())
                .then(data => 
                    for (let field in data) 
                        if (field === "jsonification") 

// I have tried using canvas.renderOnAddRemove = false to see if there was a problem //with the timing of the data being rendered and my alterations to the fill color

                            canvas.loadFromJSON(data[field]);
                            canvas.renderAll();
                        
                    
                    clientLayer();
                );
    );

//I have tried keeping this logic in the callback section of the loadOnJSON function //but got the same result.

function clientLayer()
    let objects = canvas.getObjects();
    console.log(objects);
    for (let element in objects) 
        let currentElement = objects[element];
//class is an attribute I gave to objects that were generic, the leasable objects do //not have the class attribute
        if (currentElement.class != undefined) 
            currentElement.selectable = false;
            currentElement.hoverCursor = 'default';
            canvas.sendToBack(currentElement);
         else 
 //hasControls is commented out as after I adjust the size of the object the color //will change
            // currentElement.hasControls = false;
            if (leased.includes(currentElement.id)) 
               
                currentElement.fill = 'black';
             else if (closed.includes(currentElement.id)) 
               
                currentElement.fill = 'grey';
             else 
            
                currentElement.fill = 'white';
            
        
    
//Still not too sure what the difference between requestRenderAll and renderAll is
    canvas.requestRenderAll();

This image shows that when expanded, the element has a fill attribute of white, yet it is still black.

This image was from directly after using the controls to change the size. As you can see, the rectangle is now white. But I want the rectangle to be white without having to use the controls.

【问题讨论】:

【参考方案1】:

我很高兴地宣布,我找到了解决问题的方法。在对象作为对象添加到画布元素之后,我没有更改对象,而是简单地修改了传递给 canvas.loadFromJSON 方法的 JSON。这就像一个魅力,除了当我为白色方块分配一个 strokeWidth 属性时,我得到了一些时髦的行为。不过不用担心,因为我更改了颜色以更好地适应我的整体配色方案。

let leasables = [];
let closed = [];
let available = [];
let leased = [];


window.onload = function()
    fetch("/api/leasables/get-all",method: 'GET')
        .then(response =>response.json())
        .then(data => console.log(data);
                for (let leasable in data) 
                    leasables.push(data[leasable])
                    switch (data[leasable].leasableStatus.leasableStatus) 
                        case "leased":
                            console.log(data[leasable].leasableCode);
                            leased.push(data[leasable].leasableCode);
                            break;
                        case "open":
                            console.log(data[leasable].leasableCode);
                            available.push(data[leasable].leasableCode);
                            break;
                        case "closed":
                            console.log(data[leasable].leasableCode);
                            closed.push(data[leasable].leasableCode);
                            break;
                        default: break;
                    ;
                
                return fetch("/api/configurations/load", method: 'GET')
            ).then(response => response.json())
                .then(data => 
                    for (let field in data) 
                        if (field === "jsonification") 
//Here is where the magic happens, a simple reordering of logic :)
                            let json = clientLayer(data[field]);
                            canvas.loadFromJSON(json);
                            canvas.renderAll();
                        
                    
                );
    ;

function clientLayer(unmodifiedJson)
    unmodifiedJson = JSON.parse(unmodifiedJson);
    console.log("unmodified json");
    console.log(unmodifiedJson);
    for (let element of unmodifiedJson.objects) 
        console.log("element");
        console.log(element);
        if (element.class != undefined) 
            element.selectable = false;
            element.hoverCursor = 'default';
            canvas.sendToBack(element);
         else 
            element.hasControls = false;
            element.hoverCursor = 'pointer';
            if (leased.includes(element.id)) 
                console.log("included in leased");
                element.fill = 'orange';
             else if (closed.includes(element.id)) 
                console.log("included in closed");
                element.fill = 'grey';
             else 
                console.log("included in open");
                element.fill = 'green';
                element.stroke = 'black';
                // element.strokeWidth = '0.5';
            
        
    
    let modifiedJson = unmodifiedJson;
    console.log(modifiedJson);
    return modifiedJson;
```

【讨论】:

以上是关于Fabric.js 对象在 DOM 加载时从 JSON 呈现时无法更改填充颜色的主要内容,如果未能解决你的问题,请参考以下文章

从数据 url 设置 fabric.js 画布背景

我们在 Fabric.js 中有画布修改事件吗?

使用fabric.js加载SVG中的错误图像大小

Paper.js VS EaselJS VS Fabric.js vs KineticJS

在 Fabric.js 中重置画布并使用 JSON 重新加载

fabric.js - 克隆的路径组不从 JSON 呈现