环境
框架:uniapp打包微信小程序
echarts组件:echarts-for-wx
由于自己用得饼图多个地方引用,为了复用,封装成了组件
问题
页面上有固定定位的按钮选择区域,界面内容有滚动条,但是由于canvas组件层级过高,滚动时canvas覆盖在了fixed定位的按钮选择区域
踩坑
- canvas属于小程序源生组件,层级最高,其他组件的z-index对它失效
- canvas绘制图片必须给宽高,不然会显示白板,图片绘制也是白板
- canvas导出图片必须得占用高度,但opacity和visiblity在真机都失效,display也不能使用
方案
在echarts绘制完成后,调用canvas转图片方法transformImage,将图片显示出来,canvas向左平移,完美解决
1、最外层调用饼图组件,只需要传参,没有什么特殊处理
...
<pie-chart
:canvasData="inspectorTasksStatistics.itemData"
canvasId="inspect_chart"
:nowRatio="inspectorTasksStatistics.completion_rate"
ref="piechart"
nowType="worker"
></pie-chart>
...
...
//根据ref调用peichart组件方法
this.getInspectorTasksStatistics(data).then((res) => {
try {
this.$refs.piechart.chartInit();
} catch (e) {
console.log(e);
}
});
...
2、饼图引入后,监听切换时候,先重新绘制echarts,在echarts绘制finished后调用最底层uni-ec-canvas.vue的transformImage方法,重绘图片,为了防止echarts图没有高度,通过监听值变化动态平移canvas,值变化时候先绘制canvas,有图片后,再将canvas平移,展示图片,具体操作见下chart_pie组件:
<!--echarts chart_pie饼图封装-->
<template>
<view class="canvas-wrap">
<view>
<!-- 绘制echarts区域 -->
<uni-ec-canvas
class="uni-ec-canvas"
:class="{ translateCanvas: isShowImage }"
:ref="canvasId"
canvas-id="uni-ec-canvas"
:ec="ec"
force-use-old-canvas="true"
@chartImgUrl="chartImgUrlParent"
>
</uni-ec-canvas>
</view>
<!-- 转化图片占位区域 -->
<view class="img-wrap">
<image
class="img-chart"
:src="canvasImgUrl"
v-if="isShowImage"
mode="widthFix"
></image>
</view>
</view>
</template>
<script>
import uniEcCanvas from "../../components/uni-ec-canvas/uni-ec-canvas.vue";
import * as echarts from "../../components/uni-ec-canvas/echarts";
export default {
props: {
canvasData: { type: Array },
canvasId: { type: String },
nowRatio: { tyoe: Number },
nowType: { type: String },
},
components: {
uniEcCanvas,
},
data() {
return {
ec: {
lazyLoad: true, // 延迟加载
},
canvasImgUrl: "",
isShowImage: false,
};
},
created() {},
mounted() {
try {
this.$refs[this.canvasId].init(this.initChart);
} catch (error) {
console.log(err);
}
},
methods: {
chartInit() {
this.$refs[this.canvasId].init(this.initChart);
},
initChart(canvas, width, height, canvasDpr) {
this.isShowImage = false;
let chart = null;
let that = this;
chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: canvasDpr,
});
canvas.setChart(chart);
chart.setOption(this.pieGetOption());
//echarts绘制完成
chart.on("finished", function() {
that.$refs[that.canvasId].transformImage();
this.isShowImage = true;
});
return chart;
},
//饼图
pieGetOption() {
let that = this;
let data = that.canvasData;
let colorArr = [];
if (this.nowType === "admin") {
colorArr = ["#15ADEF", "#FFBF34", "#F0230D"];
} else if (this.nowType === "worker") {
colorArr = ["#15ADEF", "#F0230D", "#FFBF34"];
}
var option = {
title: {
text: "巡检任务完成率:" + (this.nowRatio * 100).toFixed(2) + "%",
right: 10,
top: 15,
textStyle: {
fontSize: 13,
fontWeight: 400,
},
},
tooltip: {
show: false,
},
legend: {
orient: "vertical", //垂直显示
type: "scroll",
pageIconColor: "#fff", // 可以点击的翻页按钮颜色
pageIconInactiveColor: "#ccc", // 禁用的按钮颜色
y: "center", //延Y轴居中
right: 10,
top: 40,
selectedMode: false,
textStyle: {
rich: {
a: {
fontSize: 12,
padding: [0, 10, 0, 10],
width: 35,
},
b: {
fontSize: 12,
padding: [0, 10, 0, 10],
width: 35,
},
},
},
formatter: function(name) {
var target;
var total = 0;
for (var i = 0, l = data.length; i < l; i++) {
total += data[i].value;
if (data[i].name == name) {
target = data[i].value;
}
}
var arr = ["{a|" + name + "}", "{b|" + target + "}"];
return arr.join("");
},
},
color: colorArr,
series: [
{
type: "pie",
radius: "90%",
center: ["25%", "50%"],
data: that.canvasData,
label: {
//饼图图形上的文本标签
normal: {
show: true,
position: "inner", //标签的位置
textStyle: {
fontWeight: 300,
fontSize: 8, //文字的字体大小
color: "#fff",
},
formatter: "{b}:{c}",
},
},
},
],
};
return option;
},
chartImgUrlParent(src) {
this.canvasImgUrl = src;
},
},
watch: {
//根据值得变化,判断转化完图片的显示隐藏
canvasImgUrl(val, oldVal) {
if (val != oldVal) {
this.isShowImage = true;
} else {
this.isShowImage = false;
}
},
},
};
</script>
<style scoped>
.canvas-wrap,
.uni-ec-canvas,
.img-wrap {
width: 680rpx;
height: 260rpx;
}
.canvas-wrap {
position: relative;
}
.uni-ec-canvas {
position: absolute;
left: 0;
top: 0;
}
.img-wrap {
position: absolute;
left: 0;
top: 0;
background: #fff;
}
.img-chart {
width: 100%;
height: 100%;
}
.translateCanvas {
left: -1000rpx;
}
</style>
3、下载的扩展包uni-ec-canvas/uni-ec-canvas.vue添加将canvas转成转成图片的代码
methods:{
...
//将canvas转化成图片,向父组件传递生成的图片
transformImage() {
let that = this;
uni.canvasToTempFilePath(
{
canvasId: that.canvasId,
success: (res) => {
let tempFilePath = res.tempFilePath;
that.$emit("chartImgUrl", tempFilePath);
},
fail: (res) => {
console.log(res);
},
},
this
);
},
...
}
最后展示效果: