echarts 图表/SVG 图片指定位置截取
需求:如下图所示,需要固定头部legend信息
1.前期准备
echarts dom渲染容器
<div :id="'barchart' + id" class="charts" ref="barchart"></div>
- echart 图表渲染
- 取图表的echarts图片传给父组件
为什么使用setTimeout :
原因是因为防止 dom还没渲染完,echarts执行完了,会导致echarts空白的问题
myChart 为全局变量 是防止vue实时监听参数,导致浏览器卡顿或者崩溃
setTimeout(() => {
this.chartToBase64(myChart[this.id]).then((base64) => {
const direction = yAxis[0]?.type == "value" ? "l" : "p"; //PDF方向
const width = this.$refs.barchart.offsetWidth; //宽
const height = this.$refs.barchart.offsetHeight; //高
this.$emit("getBottomImag", { canvas: base64, width, height,direction })
})
},200)
// 将图表转换为 base64 字符串
chartToBase64(chart) {
return new Promise((resolve, reject) => {
chart.on("finished", () => {
resolve(chart.getDataURL({ backgroundColor: "#fff" }));
});
});
},
2.图片截取
- 父组件中创建好所需dom
<!-- 截取top bottom 图表图片 -->
<img :src="workbookTopImg" ref="topimgRef" style="position: absolute; background: #fff" v-show="workbookTopImg" />
<canvas ref="canvastop" style="visibility: hidden"></canvas>
//截取图表指定位置大小
getBottomImag(data) {
const { width, height, direction, canvas} = data;
const { offsetWidth } = this.$refs.tempRef;//获取父组件的最外层div宽度
//使导出的图表从最头开始
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
//SVG 裁剪
let imgSrc = canvas;
let img = new Image();
const _this = this;
let top = "";
img.onload = async () => {
await _this.$nextTick();
const imgTopHeight = 80;
//css 属性设定
_this.$refs.topimgRef.style.width = `${width}px`;
_this.$refs.topimgRef.style.height = `${imgTopHeight}px`;
_this.$refs.topimgRef.style.top = "70px";
_this.$refs.topimgRef.style.left = "10px";
top = {
canvas: img,
sourceX: 0,
sourceY: 0,
desiredWidth: width,
desiredHeight: imgTopHeight,
type: "top",
};
_this.workbookTopImg = await _this.cutSvgImg(top);
//用完图片后 释放缓存
img.style.display = "none";
document.body.removeChild(img);
img = null;
};
img.src = imgSrc; // 设置源路径会开始加载图像
document.body.appendChild(img);
},
- 裁取图片
//裁剪svg图片
/*canvas:裁剪的svg图片
sourceX :裁剪起点
sourceY:裁剪终点
desiredWidth:裁剪宽度
desiredHeight:裁剪高度
返回结果:裁剪后的图片 base64码
*/
async cutSvgImg({ canvas, sourceX, sourceY, desiredWidth, desiredHeight, type }) {
// 创建一个新的 canvas 来存储裁剪结果
let croppedCanvas = this.$refs["canvas" + type];
croppedCanvas.width = desiredWidth;
croppedCanvas.height = desiredHeight;
let croppedCtx = croppedCanvas.getContext("2d");
// 在裁剪 canvas 上绘制裁剪的图像部分
croppedCtx.drawImage(canvas, sourceX, sourceY, desiredWidth, desiredHeight, 0, 0, desiredWidth, desiredHeight);
const base64 = croppedCanvas.toDataURL("image/png");
// 清除canvas内容
croppedCtx.clearRect(0, 0, croppedCanvas.width, croppedCanvas.height);
// 将裁剪结果转换为 data URL
return base64;
},
3.关于drawImage参数
drawImage(image,sx,sy,swidth,sheight,x,y,width,height)
- image: 要绘制的图像,可以是图片或者canvas对象。
- sx: 图像剪切的起始X坐标。
- sy: 图像剪切的起始Y坐标。
- swidth: 图像剪切的宽度。
- sheight: 图像剪切的高度。
- x: 绘制图像的起始X坐标。
- y: 绘制图像的起始Y坐标。
- width: 绘制图像的宽度。
- height: 绘制图像的高度。
4. SVG标签中添加属性
const svg = this.$refs.barchart.getElementsByTagName("svg")[0];
svg.setAttribute("width", width);
svg.setAttribute("height", height);
svg.setAttribute("viewBox", 0 + " " + 0 + " " + width + " " + height);
5. 注意项
Canvas 的宽高设定 :
必须将canvas的宽高这样设定:<canvas id='canvas' width='300' height='400' ></canvas>
如果改为 <canvas id='canvas' style='width:300px;height:400px'></canvas>
那么将永远得到一个300*150的canvas
canvas.width 与 canvas.style.width 有什么区别呢?
canvas.width:决定canvas中有多少个像素
canvas.style.width:是canvas展示的样式大小
因此将canvas中的像素与设备分辨率保持一致,这样画布中的像素点增加,图像清晰度也就提高了
但是图片会大小会改变,因此要将图片放大相同的倍数