代码
<template>
<div style="width: calc(100vw - 300px); height: calc(80vh - 10px)">
<el-scrollbar always>
<canvas ref="canvas" id="cavsElem" :width="width" :height="height">
您的浏览器不支持canvas, 请升级更换或升级浏览器
</canvas>
</el-scrollbar>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onMounted, ref, watch } from "vue";
import { useStore } from "vuex";
import tranListToTreeData from "@/utils/tree";
import { Item } from "ant-design-vue/lib/menu";
// 字符串分割
function splitArr(arr: string | any[], num: number) {
var resultArr = [];
for (var i = 0, len = arr.length; i < len; i += num) {
resultArr.push(arr.slice(i, i + num));
}
return resultArr;
}
export default defineComponent({
setup() {
const store = useStore();
store.dispatch("financialPlan/getProductionListAndAxis", 0);
// 获取canvas实例
const canvas: any = ref(null);
const timeaxis: any = computed(() => store.state.financialPlan.axisList);
const dataList: any = computed(() => store.state.financialPlan.childlist);
const parentlist: any = computed(() => store.state.financialPlan.parentlist);
console.log(parentlist.value, 123);
const width: any = ref(0);
const height: any = ref(0);
console.log(width, height);
watch(
() => timeaxis.value,
(val) => {
console.log(123);
width.value = computed(() => timeaxis.value.length * 300 + 600).value;
height.value = computed(() => dataList.value.length * 100 + 200).value;
}
);
onMounted(() => {
const cavesSave = () => {
var ctx = canvas.value.getContext("2d");
// 获取鼠标位置
// let bgID = -1;
// canvas.addEventListener("mousemove", function(e) {
// var x = e.clientX;
// var y = e.clientY;
// var rect = canvas.getBoundingClientRect();
// x -= rect.left;
// y -= rect.top;
// console.log(x, y); // (x, y) 就是鼠标在 canvas 单击时的坐标
// console.log(parseInt(y / 100))
// ctx.clearRect(250,75,2000, 50);
// if(bgID != 0 ){
// console.log(1123123)
// ctx.beginPath()
// ctx.clearRect(250,75,2000, 50);
// ctx.clearRect(250,75,2000, 50);
// ctx.fillStyle = "rgba(0, 0, 0, 0)"
// ctx.fillRect(250,75,2000, 50);
// ctx.fill()
// }
// bgID = 2
// })
// 渲染表格
var rectH = 100;
var rectW = 300;
ctx.lineWidth = 1;
console.log(ctx);
//绘制表格
ctx.lineWidth = 1;
// 第一步: 绘制y线 和 x的值
let starty = 400; // y轴起始位置的基数
timeaxis.value.forEach((item: any, i: any) => {
ctx.setLineDash([5, 1]);
starty = item.interval * (rectW / 10) + starty;
ctx.beginPath();
ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
ctx.moveTo(starty, 0);
//如果不设置moveTo,当前画笔没有位置
ctx.lineTo(starty, canvas.value.height - 100);
ctx.stroke();
ctx.font = "16px 微软雅黑";
ctx.fillText(item.day, starty - 50, canvas.value.height - 80);
});
ctx.setLineDash([0, 0]);
//第二步:绘制横线
let startx = 400; // x轴起始位置的基数
for (var i = 0; i < 19; i++) {
ctx.beginPath();
ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
ctx.moveTo(startx, rectH * i);
ctx.lineTo(canvas.value.width - 380, rectH * i);
ctx.stroke();
}
// 数据清洗
let dataID = 0;
dataID = 0;
let dataArr2: any = [];
dataList.value.map((itemFa: any, i: any) => {
itemFa.data.map((item: any) => {
const x = dataArr2.findIndex((res: any) => res.dwID === itemFa.id);
const endTime = new Date(new Date(item.ENDTIME).getTime() + 86400000).toISOString();
if (x == -1) {
dataArr2.push({
dwID: itemFa.id,
id: dataID,
type: item.NAME,
childer: [
{
values: [
item.STARTTIME.split("T")[0].split("-").join("/"),
endTime.split("T")[0].split("-").join("/")
],
text: item.NAME,
name: item.NAME,
dwname: item.DWNAME,
planeclass: item.PLANECLASS,
drawrowno: item.DRAWROWNO,
isoverdraw: item.ISOVERDRAW,
daysprogressed: item.DAYSPROGRESSED
}
],
text: item.NAME + item.DWNAME
});
dataID++;
} else {
dataArr2[x].childer.push({
values: [item.STARTTIME.split("T")[0].split("-").join("/"), endTime.split("T")[0].split("-").join("/")],
text: item.NAME,
name: item.NAME,
dwname: item.DWNAME,
planeclass: item.PLANECLASS,
drawrowno: item.DRAWROWNO,
isoverdraw: item.ISOVERDRAW,
daysprogressed: item.DAYSPROGRESSED
});
}
});
});
// 数据条数绘制
dataArr2.forEach((res: any) => {
res.childer.forEach((resChi: any) => {
let dataStarsx =
(new Date(resChi.values[0]).getTime() - new Date(timeaxis.value[0].day).getTime()) / 86400000;
let dateTime = (new Date(resChi.values[1]).getTime() - new Date(resChi.values[0]).getTime()) / 86400000;
// 绘制 单条数据的填充
ctx.beginPath();
//
// 数据长度
let datax = dateTime * (rectW / 10);
//(x起始位置, y起始位置, 长度, 高度 )
// 填充
if (resChi.isoverdraw) {
if (resChi.drawrowno == 1) {
ctx.rect(startx + dataStarsx * (rectW / 10), res.id * 100 + 75, datax, 22);
} else {
ctx.rect(startx + dataStarsx * (rectW / 10), res.id * 100 + 75 + 29, datax, 21);
}
// 填充色
if (resChi.planeclass === 11) {
ctx.fillStyle = "#FFF2CC";
} else if (resChi.planeclass === 12) {
ctx.fillStyle = "#F2DCDA";
} else if (resChi.planeclass === 13) {
ctx.fillStyle = "#99FFCC";
} else {
ctx.fillStyle = "#00ffff";
}
ctx.strokeStyle = "rgba(0, 0, 0,1)";
ctx.stroke();
ctx.fill();
// 绘制进度方框
// 需要一个进度参数
if (resChi.drawrowno == 1) {
for (var i = 0; i < datax / (rectW / 10); i++) {
ctx.beginPath();
if (i < resChi.daysprogressed) {
ctx.lineWidth = 1;
ctx.fillStyle = "rgba(170, 0, 0, 0.5)";
ctx.fillRect(
startx + dataStarsx * (rectW / 10) + i * (rectW / 10),
res.id * 100 + 98,
rectW / 10,
5
);
}
ctx.rect(startx + dataStarsx * (rectW / 10) + i * (rectW / 10), res.id * 100 + 98, rectW / 10, 5);
ctx.strokeStyle = "rgba(0, 0, 0, 0.5 )";
ctx.stroke();
}
} else {
for (var index = 0; index < datax / (rectW / 10); index++) {
ctx.beginPath();
if (index < resChi.daysprogressed) {
ctx.lineWidth = 1;
ctx.fillStyle = "rgba(170, 0, 0, 0.5)";
ctx.fillRect(
startx + dataStarsx * (rectW / 10) + index * (rectW / 10),
res.id * 100 + 125,
rectW / 10,
5
);
}
ctx.rect(
startx + dataStarsx * (rectW / 10) + index * (rectW / 10),
res.id * 100 + 125,
rectW / 10,
5
);
ctx.strokeStyle = "rgba(0, 0, 0, 0.5 )";
ctx.stroke();
}
}
// 绘制单条数据的文本内容
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.font = "12px Arial";
let rerChiText = resChi.text;
if (resChi.dwname) rerChiText = rerChiText + `- ${resChi.dwname}`;
let textWidth = ctx.measureText(rerChiText).width;
if (textWidth < datax) {
if (resChi.drawrowno == 1) {
ctx.fillText(
rerChiText,
startx + dataStarsx * (rectW / 10) + datax / 2 - textWidth / 2,
res.id * 100 + 91
);
} else {
ctx.fillText(
rerChiText,
startx + dataStarsx * (rectW / 10) + datax / 2 - textWidth / 2,
res.id * 100 + 93 + 25
);
}
} else {
let resChiTextArr = rerChiText.split("");
let textArr = splitArr(resChiTextArr, Math.floor(rerChiText.length / 2) + 1);
textArr.forEach((resText: any, i: any) => {
ctx.fillText(
resText.join(""),
startx + dataStarsx * (rectW / 10) + datax / 2 - textWidth / 3,
res.id * 100 + (93 + i * 20)
);
});
}
} else {
let datax = dateTime * (rectW / 10);
ctx.rect(startx + dataStarsx * (rectW / 10), res.id * 100 + 75, datax, 45);
if (resChi.planeclass === 11) {
ctx.fillStyle = "#FFF2CC";
} else if (resChi.planeclass === 12) {
ctx.fillStyle = "#F2DCDA";
} else if (resChi.planeclass === 13) {
ctx.fillStyle = "#99FFCC";
} else {
ctx.fillStyle = "#00ffff";
}
ctx.strokeStyle = "rgba(0, 0, 0,1)";
ctx.stroke();
ctx.fill();
// 绘制进度方框
// 需要一个进度参数
for (var index2 = 0; index2 < datax / (rectW / 10); index2++) {
ctx.beginPath();
if (index2 < resChi.daysprogressed) {
ctx.lineWidth = 1;
ctx.fillStyle = "rgba(170, 0, 0, 0.5)";
ctx.fillRect(
startx + dataStarsx * (rectW / 10) + index2 * (rectW / 10),
res.id * 100 + 120,
rectW / 10,
10
);
}
ctx.rect(
startx + dataStarsx * (rectW / 10) + index2 * (rectW / 10),
res.id * 100 + 120,
rectW / 10,
10
);
ctx.strokeStyle = "rgba(0, 0, 0, 0.5 )";
ctx.stroke();
}
// 绘制单条数据的文本内容
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.font = "12px Arial";
let rerChiText = resChi.text;
if (resChi.dwname) rerChiText = rerChiText + `- ${resChi.dwname}`;
let textWidth = ctx.measureText(rerChiText).width;
if (textWidth < datax) {
ctx.fillText(
rerChiText,
startx + dataStarsx * (rectW / 10) + datax / 2 - textWidth / 2,
res.id * 100 + 105
);
} else {
let resChiTextArr = rerChiText.split("");
let textArr = splitArr(resChiTextArr, Math.floor(rerChiText.length / 2) + 1);
textArr.forEach((resText: any, i: any) => {
ctx.fillText(
resText.join(""),
startx + dataStarsx * (rectW / 10) + datax / 2 - textWidth / 3,
res.id * 100 + (93 + i * 20)
);
});
}
}
});
const paData = tranListToTreeData(parentlist.value, -1);
// 基数
let index = 1;
const x = (item: any, height: any, startDot: any = 0, endDot: any = 0) => {
item.map((item: any, i: any) => {
// console.log(item);
// 第一步绘制方框
ctx.beginPath();
ctx.rect(15 + (item.PLANECLASS - 1) * 200, height, 170, 25);
// 第二步绘制填充
if (item.PLANECLASS == 1) {
ctx.fillStyle = "#B7DDE8";
} else if (item.PLANECLASS == 2) {
ctx.fillStyle = "#D7E3BF";
} else if (item.PLANECLASS == 3) {
ctx.fillStyle = "#99FFCC";
}
// 第三部绘制文字
ctx.stroke();
ctx.fill();
ctx.fillStyle = "#000";
let textWidth = ctx.measureText(item.NAME).width;
ctx.fillText(item.NAME, 100 - textWidth / 2 + (item.PLANECLASS - 1) * 200, height + 15);
// 绘制连接线
if (item.PLANECLASS !== 1) {
ctx.lineWidth = 0.9;
ctx.beginPath();
ctx.moveTo(startDot, endDot + 12.5);
ctx.lineTo(startDot + 15, endDot + 12.5);
ctx.lineTo(startDot + 15, height + 12.5);
ctx.lineTo(startDot + 30, height + 12.5);
ctx.stroke();
}
if (item.PLANECLASS == 2 || item.PLANECLASS == 3) {
if (!item.children) height += 100;
}
if (item.children) {
x(item.children, height, 15 + (item.PLANECLASS - 1) * 200 + 170, height);
index++;
if (item.PLANECLASS == 1) height += index * 100;
if (item.PLANECLASS == 2) height += item.children.length * 100;
}
// height += item?.children?.length * 100 ?? 100;
});
};
x(paData, 87.5, -2);
ctx.stroke();
});
};
watch(
() => timeaxis.value,
(val) => {
cavesSave();
}
);
watch(
() => width.value,
(val) => {
console.log(val);
console.log(313123);
setTimeout(() => {
cavesSave();
}, 1);
}
);
});
return { canvas, width, height };
}
});
</script>
<style lang="scss" scoped>
:deep() .el-scrollbar__bar {
// height: 10px;
// width: 10px;
}
</style>