Javascript fabric.js调整画布大小以适应屏幕

Javascript fabric.js调整画布大小以适应屏幕,javascript,android,cordova,canvas,fabricjs,Javascript,Android,Cordova,Canvas,Fabricjs,我目前正在用ionic和cordova在移动设备(android和iPhone)上开发一个应用程序。我想编辑一张图片。我使用fabric.js库来实现这一点。Fabric.js将图像和其他项目转换为画布。然后我在画布上添加一些图像(贴纸),并将其导出为图像(dataURL)。因此画布的大小非常重要,因为它是一个质量因素(基于小画布导出图像将导致质量差)。画布大小约为607*1080像素(取决于拍摄照片的设备)。我希望在不损失质量的情况下使其适合屏幕(如下面所述,我无法在不损失质量的情况下调整画布

我目前正在用ionic和cordova在移动设备(android和iPhone)上开发一个应用程序。我想编辑一张图片。我使用fabric.js库来实现这一点。Fabric.js将图像和其他项目转换为画布。然后我在画布上添加一些图像(贴纸),并将其导出为图像(dataURL)。因此画布的大小非常重要,因为它是一个质量因素(基于小画布导出图像将导致质量差)。画布大小约为607*1080像素(取决于拍摄照片的设备)。我希望在不损失质量的情况下使其适合屏幕(如下面所述,我无法在不损失质量的情况下调整画布的大小)

我尝试了3个想法,但都没有成功

  • 调整画布大小:导致质量损失(导出的图像将具有画布大小)
  • 调整视口:cordova不允许在移动设备上更改视口。有一个解决办法,但它会打破我的设计(非常小的导航栏,较小的菜单,…)
  • 使用CSS3缩放属性:它在桌面上就像一个魔咒,但在移动设备上存在一个事件映射问题(我没有在ios上尝试,但问题发生在android Webview上)。事件映射未缩放。画布已缩小,但无法与画布元素交互。如果画布元素(贴纸)位于x:100 y:100,当我将“缩放属性”设置为0.5时,该元素将位于(50,50),而不再位于(100100)。是否有任何方法可以根据android webview的zoom属性更正事件映射
  • 我不知道是否还有其他方法可以做到这一点,但我被这个问题困扰了3天,我花了很多时间在论坛、fabricjs文档和谷歌上,我没有找到任何可行的解决方案或其他可以帮助我的东西

    编辑:下面有两个工作解决方案。查看我的答案,了解如何使用css来实现这一点。

    1。使用css设置画布的正确分辨率: css:

    优点:

    所有分辨率由画布宽度和高度(800/600)给出

    缺点:

    适合方形画布纵横比(1:1),输出有问题 对于需要计算css高度的奇怪纵横比 基于

    original height / original width * new width = new height;
    
    这是我在css中无法胜任的

    阅读不久前关于fabric.js git问题的一节,其中介绍了技术 由于速度慢和对象不正确,不建议使用(css调整大小) 事务,这可能会改变我知道我测试过的对象 重新调整大小不正确(随机彩色像素,事务阴影保留 在画布上,换句话说就是一团乱)

    2.当需要提交时,将画布重新调整为精确尺寸(分辨率),然后生成图像 只需在窗口重新调整大小(响应画布)时重新调整画布的大小,当您需要导出到精确的尺寸时,您需要将画布重新调整到精确的像素分辨率,或者创建另一个隐藏画布

    此示例适用于1:1比例的画布(您需要将纵横比应用于画布和其中的对象):

    在提交导出画布数据时,将画布重新调整为所需的分辨率,瞧:

    function GetCanvasAtResoution(newWidth)
      {
        if (canvas.width != newWidth) {
                    var scaleMultiplier = newWidth / canvas.width;
                    var objects = canvas.getObjects();
                    for (var i in objects) {
                        objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
                        objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
                        objects[i].left = objects[i].left * scaleMultiplier;
                        objects[i].top = objects[i].top * scaleMultiplier;
                        objects[i].setCoords();
                    }
    
                    canvas.setWidth(canvas.getWidth() * scaleMultiplier);
                    canvas.setHeight(canvas.getHeight() * scaleMultiplier);
                    canvas.renderAll();
                    canvas.calcOffset();
                }
         return canvas.toDataURL();
       }
       );
    

    比例不同于1:1,这没什么大不了的。你还需要计算多人游戏的高度比例,简单易懂的比例:

    我发现了一个不需要复制画布的技巧。此解决方案非常接近css缩放属性,但事件处理正确

    这是一个显示画布一半大小的示例:

    -webkit-transform : scale(0.5);
    -webkit-transform-origin : 0 0;
    

    我以前也遇到过类似的问题。我认为您应该将fabric.js计算复制到为事件所做的计算中……很多时候,用自己的方式编写代码比尝试使用打包库要好。我没有时间编写实现fabris.js中包含的所有函数性的库。我使用了这个库的很多功能,从头开始重新创建所有内容需要花费太多的时间。你可能会停止编写另一个库,然后决定与其他人共享它。有人会对图书馆有疑问,谢谢你的帮助。css裁剪图片,我的意思是如果我设置画布的宽度和高度,css将裁剪画布。但第二个似乎是一个很好的解决方案。我还找到了另一种不用复制画布的方法。我也会在这里解释,但非常感谢你的帮助。这是天才,效果不错。我在js中使用了这个技巧来缩放画布容器的比例这个技巧看起来不错,但问题是当你添加对象时,它们的控件也被缩放了太多
    $(window).resize(function (){
     if (canvas.width != $(".container").width()) {
                var scaleMultiplier = $(".container").width() / canvas.width;
                var objects = canvas.getObjects();
                for (var i in objects) {
                    objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
                    objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
                    objects[i].left = objects[i].left * scaleMultiplier;
                    objects[i].top = objects[i].top * scaleMultiplier;
                    objects[i].setCoords();
                }
    
                canvas.setWidth(canvas.getWidth() * scaleMultiplier);
                canvas.setHeight(canvas.getHeight() * scaleMultiplier);
                canvas.renderAll();
                canvas.calcOffset();
            }
    });
    
    function GetCanvasAtResoution(newWidth)
      {
        if (canvas.width != newWidth) {
                    var scaleMultiplier = newWidth / canvas.width;
                    var objects = canvas.getObjects();
                    for (var i in objects) {
                        objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
                        objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
                        objects[i].left = objects[i].left * scaleMultiplier;
                        objects[i].top = objects[i].top * scaleMultiplier;
                        objects[i].setCoords();
                    }
    
                    canvas.setWidth(canvas.getWidth() * scaleMultiplier);
                    canvas.setHeight(canvas.getHeight() * scaleMultiplier);
                    canvas.renderAll();
                    canvas.calcOffset();
                }
         return canvas.toDataURL();
       }
       );
    
    -webkit-transform : scale(0.5);
    -webkit-transform-origin : 0 0;