You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FabricJS中loadFromJSON加载视频背景空白问题(Angular6)

解决FabricJS loadFromJSON后视频背景空白的问题

我帮你排查了这个问题,核心原因是FabricJS的JSON序列化不会保存实际的DOM元素(比如video元素),只会记录对象的属性配置。所以当你调用loadFromJSON后,背景里的视频元素并没有被重新实例化,导致画布背景变成空白。下面是具体的修复方案:

关键修复点

  • 确保序列化时正确保留视频的自定义属性(你已经做了这一步,但需要在加载时正确读取)
  • 在loadFromJSON的回调函数中,重新创建video DOM元素,并将其设置为画布背景
  • 修正回调中的this指向问题,以及renderAll的调用方式(不能只bind,要实际调用)
  • 确保视频播放和渲染循环正常启动

修改后的完整代码

<button id="loadfromjson">Load from JSON</button>
<canvas id="c" width="600" height="400"></canvas>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js?v1"></script>
<script>
  var removeFromArray = fabric.util.removeFromArray;
  var custom_attributes = ['customSourceType', 'id', 'scaleMode', 'original_src', 'exclusiveName', 'video_src', 'background_image'];

  // 扩展Fabric对象的toObject方法,保留视频相关属性
  fabric.Object.prototype.toObject = (function(toObject) {
    return function(propertiesToInclude) {
      propertiesToInclude = (propertiesToInclude || []).concat([
        'video_src', 'background_image', 'src'
      ]);
      return toObject.apply(this, [propertiesToInclude]);
    };
  })(fabric.Object.prototype.toObject);

  fabric.Object.NUM_FRACTION_DIGITS = 2;
  fabric.Object.prototype.set({
    borderColor: '#00c3f9',
    cornerColor: '#00c3f9',
    cornerStrokeColor: '#ffffff',
    cornerStyle: 'circle',
    minScaleLimit: 0,
    lockScalingFlip: true,
    selectionDashArray: [5, 0],
    borderDashArray: [5, 5],
    cornerDashArray: [2, 0],
    borderScaleFactor: 1,
    cornerSize: 15,
    transparentCorners: false,
    centeredRotation: true
  });

  var canvas = new fabric.Canvas('c', {
    hoverCursor: 'pointer',
    selection: true,
    selectionBorderColor: '#00c3f9',
    selectionColor: 'rgba(0, 195, 249, 0.2)',
    preserveObjectStacking: true,
    originX: 'center',
    originY: 'center',
  });

  var url_mp4 = 'http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4';

  // 封装创建视频元素的函数,方便复用
  function getVideoElement(url, width = 400, height = 250) {
    var videoE = document.createElement('video');
    videoE.width = width;
    videoE.height = height;
    videoE.muted = true;
    videoE.crossOrigin = "anonymous";
    var source = document.createElement('source');
    source.src = url;
    source.type = 'video/mp4';
    videoE.appendChild(source);
    return videoE;
  }

  // 初始化视频背景
  function initVideoBackground(url) {
    var videoE = getVideoElement(url, canvas.width, canvas.height);
    var fab_video = new fabric.Image(videoE, {left: 0, top: 0});
    fab_video.set('video_src', url);
    fab_video.set('background_image', url);
    canvas.setBackgroundImage(fab_video);
    fab_video.getElement().volume = 0;
    fab_video.getElement().play();
    
    // 启动渲染循环,保证视频帧正常更新
    fabric.util.requestAnimFrame(function render() {
      canvas.renderAll();
      fabric.util.requestAnimFrame(render);
    });
  }

  // 初始化
  initVideoBackground(url_mp4);

  // 保存和加载事件
  $(document.body).on('click', '#loadfromjson', function(){
    console.clear();
    var json = canvas.toJSON(custom_attributes);
    canvas.loadFromJSON(json, function() {
      // 加载完成后的回调,恢复视频背景
      var canvasBG = canvas.backgroundImage;
      if(canvasBG && canvasBG.video_src) {
        initVideoBackground(canvasBG.video_src);
      }
      canvas.renderAll();
    });
  });
</script>

代码说明

  1. 封装初始化函数:把视频背景的创建逻辑封装成initVideoBackground,方便初始化和加载后重复调用
  2. 修复加载回调:在loadFromJSON的回调中,直接读取背景对象的video_src属性,调用初始化函数重建视频背景
  3. 修正渲染逻辑:确保渲染循环正确启动,保证视频帧能持续更新到画布上
  4. 统一尺寸处理:创建视频元素时使用画布的宽高,避免尺寸不匹配

这样修改后,你点击Load from JSON按钮时,视频背景就能正常恢复了。

内容的提问来源于stack exchange,提问作者Umesh Patadiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:17:22