一次svg加载问题的处理

svg的渲染问题

背景

在一个使用bpmn渲染工作流的项目中,发现了图形偏移的问题,如图所示:

在这里插入图片描述

最初的解决方案是调整位置,结果并不能解决问题。

模板部分

 <div class="flow-containers">
     <el-container class="bpmn-el-container" style="align-items: stretch">
         <el-main style="padding: 0">
             <div ref="canvas" class="canvas" />
         </el-main>
     </el-container>
</div>

脚本部分(只展示了有用的)

const canvas = ref<HTMLElement>();
const modeler = ref<BpmnViewer>();
const taskList = ref([]);
const zoom = ref(1);
const xml = ref('');
const loading = ref(false);
const bpmnVisible = ref(true);
const historyList = ref([]);
    
// 让图能自适应屏幕
const fitViewport = () => {
  modeler.value.get<Canvas>('canvas').viewbox();
  zoom.value = modeler.value.get<Canvas>('canvas').zoom('fit-viewport');
  //获取svg的大小
  const bbox = document.querySelector<SVGGElement>('.flow-containers .viewport').getBBox();
  const currentViewBox = modeler.value.get<Canvas>('canvas').viewbox();
  console.log(bbox);
  console.log(currentViewBox);
  //通过这个来调整bpnm的渲染图的位置
  const elementMid = {
    x: bbox.x + bbox.width / 2,
    y: bbox.y + bbox.height / 2
  };
  console.log(elementMid);
  // 最后生成的是一张svg,核心位置属性就是viewbox
  modeler.value.get<Canvas>('canvas').viewbox({
    x: elementMid.x - currentViewBox.width / 2,
    y: elementMid.y - currentViewBox.height / 2,
    width: currentViewBox.width,
    height: currentViewBox.height
  });
  zoom.value = (bbox.width / currentViewBox.width) * 1.8;
};

定位问题

在问题项目中,多处用到了bpmnView组件,所以在之前的代码中有多次销毁重置的过程(我们不去纠结这是否合理,在修复老项目的过程中,优先解决现有问题,在考虑是否应该优化),后来定位问题是在使用getBox获取svg属性时,获取到的属性为:

SVGRect {
    x: 0, 
    y: 0, 
    width: 0, 
    height: 0
}

getBBox()

简介

**SVGGraphicsElement.getBBox()**允许我们确定对象适合的最小矩形的坐标。返回一个DOMRect,它表示当前元素的计算出的边界框。

返回的坐标是相对于当前 svg 空间的,即在将所有几何属性应用于目标元素中包含的所有元素之后。

解释

它是svg元素的专用API之一,用于获取svg元素的位置属性,例如坐标点、宽、高等等。

问题原因及解决方案

产生该问题的原因时我们在svg的g标签还没有加载完成时就使用了getBBox().

解决方案

我们可以在svg元素上添加load监听事件,在svg元素加载完成后在继续执行之前的逻辑,语法为:

svgDom.addEventListener("load",()=>{
    //svg元素成功加载完成后再触发
})

修复后的脚本

// 让图能自适应屏幕
const fitViewport = () => {
  modeler.value.get<Canvas>('canvas').viewbox();
  zoom.value = modeler.value.get<Canvas>('canvas').zoom('fit-viewport');
  const bboxSvg = document.querySelector<SVGGElement>('.flow-containers .viewport');
  //svg元素加载完成再获取
  bboxSvg.addEventListener('load', () => {
    //获取svg的大小
    const bbox = bboxSvg.getBBox();
    const currentViewBox = modeler.value.get<Canvas>('canvas').viewbox();
    console.log(bbox);
    console.log(currentViewBox);
    //通过这个来调整bpnm的渲染图的位置
    const elementMid = {
      x: bbox.x + bbox.width / 2,
      y: bbox.y + bbox.height / 2
    };
    console.log(elementMid);
    // 最后生成的是一张svg,核心位置属性就是viewbox
    modeler.value.get<Canvas>('canvas').viewbox({
      x: elementMid.x - currentViewBox.width / 2,
      y: elementMid.y - currentViewBox.height / 2,
      width: currentViewBox.width,
      height: currentViewBox.height
    });
    zoom.value = (bbox.width / currentViewBox.width) * 1.8;
  });
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值