天道酬勤,学无止境

Fabric.js-如何使用自定义属性在服务器上保存画布(Fabric.js - how to save canvas on server with custom attributes)

问题

我希望能够将当前canvas的状态保存为服务器端数据库(可能作为JSON字符串),然后再使用loadFromJSON还原它。 通常,使用以下方法可以轻松实现此目的:

var canvas = new fabric.Canvas();
function saveCanvas() {
    // convert canvas to a json string
    var json = JSON.stringify( canvas.toJSON() );

    // save via xhr
    $.post('/save', { json : json }, function(resp){ 
        // do whatever ...
    }, 'json');
}

进而

function loadCanvas(json) {

  // parse the data into the canvas
  canvas.loadFromJSON(json);

  // re-render the canvas
  canvas.renderAll();

  // optional
  canvas.calculateOffset();
}

但是,我还使用内置的Object#set方法在要添加到画布上的结构对象上设置了一些自定义属性:

// get some item from the canvas
var item = canvas.item(0);

// add misc properties
item.set('wizard', 'gandalf');
item.set('hobbit', 'samwise');

// save current state
saveCanvas();

问题是,当我在服务器端检查请求时,我看到我的自定义属性没有从画布中解析出来,而是随其他内容一起发送。 这可能与toObject方法如何删除对象类中不是默认属性的所有内容有关。 什么是解决此问题的好方法,这样我就可以从服务器发送的JSON字符串中保存还原画布,并且还原的画布还将包含我的自定义属性? 谢谢。

回答1

好问题。

如果要向对象添加自定义属性,则这些对象在某种程度上可能是“特殊的”。 似乎将它们子类化是一个合理的解决方案。

例如,这是我们将fabric.Image子类化为命名图像的方法。 这些图像对象然后可能具有“ Gandalf”或“ Samwise”之类的名称。

fabric.NamedImage = fabric.util.createClass(fabric.Image, {

  type: 'named-image',

  initialize: function(element, options) {
    this.callSuper('initialize', element, options);
    options && this.set('name', options.name);
  },

  toObject: function() {
    return fabric.util.object.extend(this.callSuper('toObject'), { name: this.name });
  }
});

首先,我们给这些对象一个类型。 loadFromJSON使用此类型来自动调用fabric.<type>.fromObject方法。 在这种情况下,它将是fabric.NamedImage.fromObject

然后,我们覆盖initialize (构造函数)实例方法,以便在初始化对象时也设置“ name”属性(如果提供了该属性)。

然后,我们覆盖toObject实例方法以在返回的对象中包含“名称”(这是结构中对象序列化的基石)。

最后,我们还需要实现我前面提到的fabric.NamedImage.fromObject ,以便loadFromJSON知道在JSON解析期间要调用的方法:

fabric.NamedImage.fromObject = function(object, callback) {
  fabric.util.loadImage(object.src, function(img) {
    callback && callback(new fabric.NamedImage(img, object));
  });
};

我们正在此处加载图像(来自“ object.src”),然后fabric.NamedImage创建fabric.NamedImage的实例。 请注意,由于我们之前改写了“ initialize”方法,因此构造方法已经可以处理“名称”设置了。

并且我们还需要指定fabric.NamedImage是一个异步“类”,这意味着其fromObject不会返回实例,而是将其传递给回调:

fabric.NamedImage.async = true;

现在我们可以尝试一下:

// create image element
var img = document.createElement('img');
img.src = 'https://www.google.com/images/srpr/logo3w.png';

// create an instance of named image
var namedImg = new fabric.NamedImage(img, { name: 'foobar' });

// add it to canvas
canvas.add(namedImg);

// save json
var json = JSON.stringify(canvas);

// clear canvas
canvas.clear();

// and load everything from the same json
canvas.loadFromJSON(json, function() {

  // making sure to render canvas at the end
  canvas.renderAll();

  // and checking if object's "name" is preserved
  console.log(canvas.item(0).name);
});
回答2

哇。 我在这里想念什么吗?

我已经做了很多次,不需要任何花哨的子类化。

文档涵盖了它:http://fabricjs.com/docs/fabric.Canvas.html#toJSON

只需在对toJSON()的调用中包含属性名称数组作为字符串即可。

例如

canvas.toJSON(['wizard','hobbit']);

希望...。对于奖励积分,您可以添加一个reviver函数,该函数将为您的自定义属性补水。

再次在文档中进行了介绍,并有一个示例。

回答3

我有同样的问题,但是我不想扩展fabric.js类。

我编写了一个函数,该函数将fabric canvas作为参数,并返回带有特殊属性的字符串化版本:

function stringifyCanvas(canvas)
{
    //array of the attributes not saved by default that I want to save
    var additionalFields = ['selectable', 'uid', 'custom']; 

    sCanvas = JSON.stringify(canvas);
    oCanvas = JSON.parse(sCanvas) ;
    $.each(oCanvas.objects, function(n, object) {
        $.each(additionalFields, function(m, field) {
            oCanvas.objects[n][field] = canvas.item(n)[field];
        });
    });

    return JSON.stringify(oCanvas);     
}

当我使用canvas.loadFromJSON() Fabric 1.7.2时,特殊属性似乎已正确导入。

回答4

一种更简单的方法是在字符串化后添加属性:

var stringJson = JSON.stringify(this.canvas);
var objectJson = JSON.parse(string.Json);

//remove property1 property
delete objectJson.property1;

//add property2 property
delete objectJson.property2;

// stringify the object again
stringJson = JSON.stringify(objectJson);

// at this point stringJson is ready to be sent over to the server
$http.post('http://serverurl/',stringJson);
回答5

如果不想每次调用canvas.toJSON()时都指定要使用的自定义属性,并且不想使用复杂的子类化方法,则这是扩展Fabric的toObject方法的一种非常简单的方法。

//EXTEND THE PROPS FABRIC WILL EXPORT TO JSON
fabric.Object.prototype.toObject = (function(toObject) {
    return function() {
        return fabric.util.object.extend(toObject.call(this), {
            id: this.id,
            wizard: this.wizard,
            hobbit: this.hobbit,
        });
    };
})(fabric.Object.prototype.toObject);

然后,您可以在Fabric对象上设置自定义属性。

item.set("wizard","gandalf");
item.set("hobbit","bilbo");

当您调用canvas.toJSON()这些属性将保留到输出中。 然后,如果将canvas.loadFromJSON()与JSON输出一起使用,则将导入自定义属性并将其应用于Fabric对象。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • canvas.toDataURL()SecurityError(canvas.toDataURL() SecurityError)
    问题 所以我正在使用谷歌地图,我得到的照片看起来像这样 <img id="staticMap" src="http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap &markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318 &markers=color:red%7Ccolor:red%7Clabel:C%7C40.718217,-73.998284&sensor=false"> 我需要保存它。 我发现了这一点: function getBase64FromImageUrl(URL) { var img = new Image(); img.src = URL; img.onload = function() { var canvas = document.createElement("canvas"); canvas.width = this.width; canvas.height = this.height; var ctx = canvas
  • 为什么canvas.toDataURL()抛出安全异常?(Why does canvas.toDataURL() throw a security exception?)
    问题 我睡眠不足吗? 下面的代码 var frame=document.getElementById("viewer"); frame.width=100; frame.height=100; var ctx=frame.getContext("2d"); var img=new Image(); img.src="http://www.ansearch.com/images/interface/item/small/image.png" img.onload=function() { // draw image ctx.drawImage(img, 0, 0) // Here's where the error happens: window.open(frame.toDataURL("image/png")); } 抛出此错误: SECURITY_ERR: DOM Exception 18 这是不可能的,这是行不通的! 有人可以解释一下吗? 回答1 在规格中它说: 每当调用其origin-clean标志设置为false的canvas元素的toDataURL()方法时,该方法都必须引发SECURITY_ERR异常。 如果图像来自其他服务器,我认为您不能使用toDataURL() 回答2 在对我有用的图像对象上设置跨原点属性(我正在使用fabricjs) var c =
  • 区块链性能测试工具caliper
    Caliper是一个区块链性能测试框架,可用于测试不同的区块链实现。支持 fabric v1.0+ sawtooth 1.0+ Iroha 1.0 测试内容指标包括: 交易成功率 交易吞吐量TPS 交易延迟 资源消耗 感受一下先 准备 先安装NodeJS 8.X、node-gyp、Docker、Docker-compose。 git clone https://github.com/hyperledger/caliper.git cd caliper npm install 安装区块链SDK(以fabric为例) # caliper项目目录下 npm install grpc@1.10.1 fabric-ca-client fabric-client 跑个测试 性能测试示例在benchmark目录下,用法如下: node benchmark/simple/main.js -c yourconfig.json -n yournetwork.json -c用于指定区块链的配置文件,不指定的话默认为config.json; -n用于指定区块链网络配置文件,不指定的话由-c指定的配置文件定义。 跑一个smallbank的例子: node benchmark/smallbank/main.js 生成的报告长这样(部分): 架构 在这个标准框架核心,是可以译解信息的“适配层”
  • How does transforming points with a transformMatrix work in fabricJS?
    I'm trying to place points (made via fabric.Circle) on the corners of a fabric.Polygon. The polygon may be moved, scaled or rotated by the user. However, after each modification I want to have the new coordinates of the polygon to place my circles there. While digging deeper into this topic I found this great explanation of transformation matrices. I thought it's the perfect solution for what I want to achieve. But as you can see in the Fiddle, my points are always way off my polygon. As I'm not firm with geometric transformation etc. I hope someone can find my error and tell me what I'm
  • Multiple clipping areas on Fabric.js canvas
    For making Photo Collage Maker, I use fabric js which has an object-based clipping feature. This feature is great but the image inside that clipping region cannot be scaled, moved or rotated. I want a fixed position clipping region and the image can be positioned inside the fixed clipping area as the user want. I googled and find very near solution. var canvas = new fabric.Canvas('c'); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.rect(10,10,150,150); ctx.rect(180,10,200,200); ctx.closePath(); ctx.stroke(); ctx.clip(); Multiple Clipping Areas on fabric js canvas where the image of
  • Fabric.js - how to save canvas on server with custom attributes
    I'd like to be able to save the current canvas' state to a server-side database, probably as a JSON string, and then later restore it with loadFromJSON. Typically, this is easily accomplished using: var canvas = new fabric.Canvas(); function saveCanvas() { // convert canvas to a json string var json = JSON.stringify( canvas.toJSON() ); // save via xhr $.post('/save', { json : json }, function(resp){ // do whatever ... }, 'json'); } And then function loadCanvas(json) { // parse the data into the canvas canvas.loadFromJSON(json); // re-render the canvas canvas.renderAll(); // optional canvas
  • Fit the background image to canvas size with Fabric js
    I am trying to stretch the background image so it can fit the canvas size. But its not working. I have followed this question and based on comment i have implemented the stretching code. Strech the background image to canvas size with Fabric.js http://fabricjs.com/docs/fabric.Canvas.html#setBackgroundImage Code $(function () { var canvas1 = new fabric.Canvas('canvas1'); //Default var canvas = canvas1; //Change background using Image document.getElementById('bg_image').addEventListener('change', function (e) { canvas.setBackgroundColor('', canvas.renderAll.bind(canvas)); canvas
  • Download Canvas as PNG in fabric.js giving network Error
    I want to download Canvas as PNG using fabric.js. While downloading I want to scale the image. So I use multiplier property of toDataURL() function. But I get Failed-Network Error PS: If I dont give multiplier property,it is downloading but I do want to use multiplier property since I have to scale the image This is what I am doing: HTML Code: <canvas width="400" height="500" id="canvas" ></canvas> <a id='downloadPreview' href="javascript:void(0)"> Download Image </a> JS document.getElementById("downloadPreview").addEventListener('click', downloadCanvas, false); var _canvasObject = new fabric
  • How to make rooftext effect and valley text effect in HTML5 (or Fabric.js)
    I am using below code: <script type='text/javascript'>//<![CDATA[ window.onload=function(){ /// (c) Ken Fyrstenberg Nilsen, Abidas Software .com /// License: CC-Attribute var ctx = demo.getContext('2d'), font = '64px impact', w = demo.width, h = demo.height, curve, offsetY, bottom, textHeight, angleSteps = 255/h, i = h, y, os = document.createElement('canvas'), octx = os.getContext('2d'); os.width = w; os.height = h; octx.font = font; octx.textBaseline = 'top'; octx.textAlign = 'center'; function renderBridgeText() { curve = parseInt(iCurve.value, 10); offsetY = parseInt(iOffset.value, 10)
  • 如何在画布上绘制内嵌svg(在DOM中)?(How to draw an inline svg (in DOM) to a canvas?)
    问题 好吧,我需要一些有关将.svg文件/图像转换为.png文件/图像的帮助... 我的页面上显示了一个.svg图像。 它保存在我的服务器上(.png文件)。 我需要按需将其转换为.png文件(单击按钮),然后将.png文件保存在服务器上(我将通过.ajax请求执行此操作)。 但是问题是转换。 我阅读了很多有关html5 Canvas的内容,这些内容可能可以帮助我做我现在需要做的事情,但是我找不到解决我问题的明确方法,而且,我不明白我所发现的一切...所以我需要一些明确的建议/帮助,以帮助我了解如何做。 这是“ html idea”模板: <html> <body> <svg id="mySvg" width="300px" height="300px"> <!-- my svg data --> </svg> <label id="button">Click to convert</label> <canvas id="myCanvas"></canvas> </body> </html> 和一些js: <script> $("body").on("click","#button",function(){ var svgText = $("#myViewer").outerHTML; var myCanvas = document.getElementById("canvas")
  • 如何清除画布以重画(How to clear the canvas for redrawing)
    问题 在尝试了复合操作并在画布上绘制图像之后,我现在尝试删除图像并进行合成。 我该怎么做呢? 我需要清除画布才能重画其他图像; 这可能会持续一段时间,所以我不认为每次都绘制一个新的矩形将是最有效的选择。 回答1 假设canvas是canvas元素, const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); 回答2 使用: context.clearRect(0, 0, canvas.width, canvas.height); 这是清除整个画布的最快,最具描述性的方法。 不要使用: canvas.width = canvas.width; 重置canvas.width重置所有画布状态(例如,转换,lineWidth,strokeStyle等),它非常慢(与clearRect相比),在所有浏览器中均不起作用,并且无法描述您实际尝试的操作去做。 处理变换后的坐标 如果你已经修改了变换矩阵(例如,使用scale , rotate或translate ),然后context.clearRect(0,0,canvas.width,canvas.height)可能不会清除画布的整个可见部分。 解决方案? 在清除画布之前,请重置转换矩阵: // Store the
  • 如何在浏览器中通过Javascript压缩图像?(How to compress an image via Javascript in the browser?)
    问题 TL; DR; 上传之前,有没有一种方法可以直接在浏览器端压缩图像(主要是jpeg,png和gif)? 我很确定JavaScript可以做到这一点,但是我找不到实现它的方法。 这是我要实现的完整方案: 用户访问我的网站,并通过input type="file"元素选择图片, 该图片是通过JavaScript检索的,我们进行了一些验证,例如正确的文件格式,最大文件大小等, 如果一切正常,则会在页面上显示图像的预览, 用户可以执行一些基本操作,例如将图像旋转90°/ -90°,按照预定义的比例进行裁剪等,或者用户可以上传其他图像并返回到第1步当用户满意时,然后将编辑后的图像压缩并本地“保存”(不保存到文件中,而是保存在浏览器的内存/页面中),- 用户使用姓名,年龄等数据填写表单, 用户单击“完成”按钮,然后将包含数据和压缩图像的表单发送到服务器(不使用AJAX), 直到最后一步的整个过程都应该在客户端完成,并且应该与最新的Chrome和Firefox,Safari 5+和IE 8+兼容。 如果可能的话,应该只使用JavaScript(但我很确定这是不可能的)。 我现在还没有编写任何代码,但是我已经考虑过了。 可以通过File API在本地读取文件,可以使用Canvas元素完成图像预览和编辑,但是我找不到找到图像压缩部分的方法。 根据html5please.com和caniuse
  • 如何修复getImageData()错误画布已被跨域数据污染?(How to fix getImageData() error The canvas has been tainted by cross-origin data?)
    问题 我的代码在localhost上运行良好,但在站点上不运行。 我从控制台收到此行.getImageData(x,y,1,1).data : Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 我的代码的一部分: jQuery.Event.prototype.rgb=function(){ var x = this.offsetX || (this.pageX - $(this.target).offset().left),y = this.offsetY || (this.pageY - $(this.target).offset().top); if (this.target.nodeName!=="CANVAS")return null; return this.target.getContext('2d').getImageData(x,y,1,1).data; } 注意:我的图片网址(src)来自子域网址 回答1 正如其他人所说,您是通过从跨起源域加载来“污染”画布的。 https://developer.mozilla.org/zh-CN/docs
  • HTML5画布到PNG文件(HTML5 Canvas to PNG File)
    问题 我正在尝试将HTML5画布转换为图像。 这是我到目前为止所得到的: var tmp_canvas = document.getElementById('canvas'); var dataURL = tmp_canvas.toDataURL("image/png"); $('#thumbnail_list').append($('<img/>', { src : dataURL }).addClass('image')); 但是问题是我得到了以下代码: <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAYAAADtt+XCAAAgAElEQVR4nNS6Z1xVaZbvv/c+CVOZc6mYEMlJMZRizgljGRARs6AgOSMGQATBSM5ZyTkoOQkSzJWrp3t6etLt6Z7pmf/c++L7f3EOiBZW2dM9dz73xfdzztl7n3Oe/Txrrd9a69mCTC4gkwvIZAKSTECUBARRQBA+jii+46f.......class="image"> 我想要用户可以下载的普通图像路径! 有什么帮助吗? 回答1 信息: IE10 +完全不支持以下方法。 其他人已经完成了工作并实现了跨浏览器解决方案。 这就是其中之一。 首先,将生成的数据URL添加到
  • 如何使用canvas.toDataURL()将画布另存为图像?(How To Save Canvas As An Image With canvas.toDataURL()?)
    问题 我目前正在构建HTML5 Web应用程序/ Phonegap本机应用程序,但似乎无法弄清楚如何使用canvas.toDataURL()将画布另存为图像。 有人可以帮我吗? 这是代码,这是怎么回事? //我的画布被命名为“ canvasSignature” JavaScript: function putImage() { var canvas1 = document.getElementById("canvasSignature"); if (canvas1.getContext) { var ctx = canvas1.getContext("2d"); var myImage = canvas1.toDataURL("image/png"); } var imageElement = document.getElementById("MyPix"); imageElement.src = myImage; } HTML5: <div id="createPNGButton"> <button onclick="putImage()">Save as Image</button> </div> 回答1 这是一些代码。 没有任何错误。 var image = canvas.toDataURL("image/png").replace("image/png", "image
  • Photoshop入门教程十个点
    Adobe Photoshop是目前最流行的平面设计软件之一。可以说,只要你接触平面设计,那么无论早晚,你都要和它打交道。关于Photoshop,要说的实在太多太多,但不论你想让它成为你的左膀右臂,或者仅仅是用它来做一些最基础的图像处理工作,那么下面的10件事都是你一定要知道的,无论你是个初学者或是已经对它有了一定的了解。1.快捷键的使用:这是Photoshop基础中的基础,却也是提高工作效率的最佳方法。快捷键的使用,使你可以将精力更好的集中在你的作品而不是工具面板上。一旦你能够熟练的使用快捷键,你就可以使用全屏的工作方式,省却了不必要的面板位置,使视野更开阔,最大限度的利用屏幕空间;一些简单的命令可以用键盘来完成,不必分心在工具的选择上,哪怕它只占用了极少的时间,但我们更希望在工作时不被打断。注意:你应该尽量多使用快捷键,下面的这些快捷键是提高效率的好帮手,但不知为什么很多书中都一带而过,甚至没有提及,请一定要牢牢记住。Ctrl+J:复制当前图层到一个新层;J:切换到喷枪工具;M:切换到选框工具;[ ]:在当前工具为画笔模式时(包括喷枪、画笔、铅笔、仿制图章历史画笔、橡皮及模糊和加深等工具),依次增减笔头大小;Shift+BackSpace:调出填充对话框。一开始,你可能无法记住所有的快捷键,可以使用Photoshop的工具提示来帮助你。方法是打开编辑>预置>常规,选择
  • 来自DataURL的Blob?(Blob from DataURL?)
    问题 使用FileReader的readAsDataURL()我可以将任意数据转换为Data URL。 有没有办法使用内置的浏览器API将数据URL转换回Blob实例? 回答1 用户Matt一年前提出了以下代码(如何在javascript中将dataURL转换为文件对象?),这可能对您有帮助 编辑:正如一些评论者所报告的,BlobBuilder已被弃用了一段时间。 这是更新的代码: function dataURItoBlob(dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this var byteString = atob(dataURI.split(',')[1]); // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] // write the bytes of the string to an ArrayBuffer var ab = new ArrayBuffer
  • 如何修复HTML5画布中的模糊文本?(How do I fix blurry text in my HTML5 canvas?)
    问题 我总的n00b HTML5和我有工作canvas渲染形状,颜色和文字。 在我的应用程序中,我有一个视图适配器,可以动态创建画布,并用内容填充它。 效果非常好,除了我的文本非常模糊/模糊/拉伸。 我还看到了许多其他文章,说明为什么在CSS定义宽度和高度会导致此问题,但我在javascript都定义了这些内容。 相关代码(查看小提琴): var width = 500;//FIXME:size.w; var height = 500;//FIXME:size.h; var canvas = document.createElement("canvas"); //canvas.className="singleUserCanvas"; canvas.width=width; canvas.height=height; canvas.border = "3px solid #999999"; canvas.bgcolor = "#999999"; canvas.margin = "(0, 2%, 0, 2%)"; var context = canvas.getContext("2d"); ////////////////// //// SHAPES //// ////////////////// var left = 0; //draw zone 1 rect context
  • What is the best practice to export canvas with high quality images?
    I need your help. I explain my situation: I’m using fabric.js library to place shapes, text, etc. in my application. My canvas size has 1000x1000 pixels (about 26.45x26.45 centimeters). I have an image upload script only for upload images in high quality, like 300 dpi. Basically what I do is the following: - draw the canvas (uploading images, put text, etc…); - resize the canvas multiplying by scale factor to be able at the end to have an image with 300dpi; - save the canvas in PNG format; - using php/ajax and Imagick, put the canvas with 300 dpi quality, saving in jpg format. The problem is
  • 画布中鼠标的实际位置[重复](Real mouse position in canvas [duplicate])
    问题 这个问题已经在这里有了答案: 如何获得在画布元素上单击鼠标的坐标? (22个答案) 1年前关闭。 我正在尝试用鼠标在HTML5画布上绘制,但是似乎正常工作的唯一方法是,如果出于某种原因,如果我更改了画布的位置,那么画布是否位于0,0(左上角)的位置它不会像应该的那样绘制。 这是我的代码。 function createImageOnCanvas(imageId){ document.getElementById("imgCanvas").style.display = "block"; document.getElementById("images").style.overflowY= "hidden"; var canvas = document.getElementById("imgCanvas"); var context = canvas.getContext("2d"); var img = new Image(300,300); img.src = document.getElementById(imageId).src; context.drawImage(img, (0),(0)); } function draw(e){ var canvas = document.getElementById("imgCanvas"); var context =