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;
});
};