当前位置: 首页 > news >正文

使用uni-app和Canvas生成简易双列表格布局并长按下载到本地

在现代Web和移动应用开发中,Canvas技术为我们提供了强大的图形绘制能力。本文将介绍如何使用uni-app框架结合Canvas技术,创建一个美观的健康风险评估报告页面,并实现长按保存功能。

实现思路

1. Canvas基础设置

首先,我们需要设置Canvas画布并获取其实际尺寸:

2. 获取Canvas尺寸

使用uni-app的API(createSelectorQuery)获取Canvas的实际尺寸:

3. 绘制双列表格

核心的绘制函数drawCanvas实现了双列表格布局,左侧key右侧对应value

完整代码如下

<template><view class="canvaspage"><canvasstyle="width: 100%; height: 100vh"class="canvas"ref="canvasbox"canvas-id="canvasbox"@longpress="downloadPic(state.createImgPath)"></canvas></view>
</template><script setup lang="ts">
import { getCanvasSize } from "@/utils/canvas";
import { ref, onMounted, getCurrentInstance, nextTick, reactive } from "vue";
import { downloadPic } from "@/utils/common";const canvasbox = ref<HTMLCanvasElement | null | any>(null);
const instance = getCurrentInstance();
const state = reactive({createImgPath: "",
});onMounted(() => {console.log("onMounted", instance);nextTick(() => {drawCanvas();});
});async function drawCanvas() {const context = uni.createCanvasContext("canvasbox");const res = await getCanvasSize(".canvas", instance?.proxy);context.setFillStyle("white"); //全局背景const width = res.width;const startY = 50; // 脑卒中标准 Y轴起始位置  30为上下间距setCutLine(context, { x: 12, y: 30 }, width); // 分割线// 重新计算布局const leftMargin = 12; // 左边距const rightMargin = 12; // 右边距const tableWidth = width - leftMargin - rightMargin; // 表格总宽度const columnWidth = tableWidth / 2; // 每列宽度(平均分配)// 左列和右列的起始位置const leftColumnStart = leftMargin;const rightColumnStart = leftMargin + columnWidth;// 更精确的文本宽度估算函数const estimateTextWidth = (text: string) => {let width = 0;for (let i = 0; i < text.length; i++) {const char = text[i];if (/[\u0000-\u00FF]/.test(char)) {// 英文字符或数字width += 7;} else {// 中文字符width += 14;}}return width;};standardList().forEach((item: any, index: any) => {const y = index ? index * 30 + startY : startY;// 估算文本宽度const keyWidth = estimateTextWidth(item.key);const valueWidth = estimateTextWidth(item.value);// 计算左侧文本X坐标,使其在左列居中const tNumX = leftColumnStart + (columnWidth - keyWidth) / 2;// 计算右侧文本X坐标,使其在右列居中const vNumX = rightColumnStart + (columnWidth - valueWidth) / 2;context.setFillStyle("#333333");context.setFontSize(14); // 设置字体大小// 调整Y坐标,使文本垂直居中const textY = y - 2; // 向上偏移一点,使文本在行中垂直居中context.fillText(item.key, tNumX, textY);context.fillText(item.value, vNumX, textY);// 分割线setCutLine(context, { x: 12, y: y + 8 }, width);});// 画竖线context.lineWidth = 1;context.strokeStyle = "#E5E5E5";context.beginPath();const lineY = 30;const endY = standardList().length * 30 - 2 + lineY;// 竖线context.moveTo(leftColumnStart, lineY); // 左context.lineTo(leftColumnStart, endY);context.moveTo(rightColumnStart, lineY); // 中context.lineTo(rightColumnStart, endY);context.moveTo(width - rightMargin, lineY); // 右context.lineTo(width - rightMargin, endY);context.stroke();context.setFontSize(42);context.setFillStyle("red");context.setTextAlign("center");context.setTextBaseline("middle");context.fillText("长按点击下载", width / 2, res.height - 300);context.draw(false, () => {uni.canvasToTempFilePath({canvasId: "canvasbox",success: (result: any) => {state.createImgPath = result.tempFilePath;},});});
}// 分割线
const setCutLine = (ctx: any, xy: any, width?: any) => {const startX = 12;ctx.lineWidth = 1;ctx.beginPath();ctx.moveTo(xy.x, xy.y + 0.5); // + 0.5 线像素为1pxctx.lineTo(width ? width - startX : startX, xy.y + 0.5);ctx.closePath();ctx.strokeStyle = "#E5E5E5";ctx.stroke();
};//  标准列表
const standardList = () => {return [{key: "高血压",value: "≥140/90mmHg",},{key: "血脂情况",value: "血脂异常或不知道",},{key: "糖尿病",value: "有",},{key: "心房颤动",value: "心跳不规则",},{key: "吸烟",value: "有",},{key: "体重",value: "明显超重或肥胖",},{key: "运动",value: "缺乏运动",},{key: "是否抽烟",value: "是的",},{key: "是否喝酒",value: "是的",},{key: "是否患有精神洁癖",value: "不曾",},];
};
</script><style scoped lang="scss">
.canvaspage {width: 100%;min-height: 100vh;box-sizing: border-box;padding: 32rpx;
}
</style>

应用场景

这种技术可以广泛应用于:

健康评估报告生成

电子病历可视化

体检结果展示

医疗数据报告

引入方法补充

getCanvasSize方法

//获取canvas画布的实际尺寸
export const getCanvasSize = (classname: any, nodeInfo: any): Promise<any> => {return new Promise((resolve, reject) => {const query = uni.createSelectorQuery().in(nodeInfo);query.select(classname).fields({ size: true }, (res: any) => {if (res) {resolve(res);} else {reject("获取画布尺寸失败");}}).exec();});
};

downpic方法--参考本篇文章:

uni微信小程序实现保存图片到本地_uniapp保存图片到相册-CSDN博客

希望本文对你在uni-app中使用Canvas有所帮助!

http://www.dtcms.com/a/355275.html

相关文章:

  • 混淆 打包 编译
  • Ovis2.5技术解密:原生分辨率与“反思模式”如何铸就新一代MLLM王者
  • 2024年山东省信息学小学组(CSP-X)第一轮题解
  • 冒泡排序算法详解(python code)
  • Python训练营打卡 DAY 50 预训练模型+CBAM模块
  • Shell 编程基础与实践要点梳理
  • PCIe 5.0 SSD连续读写缓存用完速度会骤降吗?
  • IntelliJ IDEA 反编译JAR包记录
  • Beats与Elasticsearch高效数据采集指南
  • Komo Searc-AI驱动的搜索引擎
  • 控制系统仿真之PID校正1-系统固有属性(四)
  • 【ai编辑器】使用cursor-vip获得cursor的pro版 pro plan(mac)
  • 【C语言16天强化训练】从基础入门到进阶:Day 13
  • 模拟实现Linux中的进度条
  • 带动态条件的模糊查询SQL
  • 【Linux基础知识系列:第一百一十四篇】使用lsof查看打开的文件
  • frp 一个高性能的反向代理服务
  • VMware + Ubuntu 桥接模式不能联网 的常见原因、排查思路和解决步骤
  • element-plus的el-scrollbar显示横向滚动条
  • 整体设计 修订 之1 三“先”之“基” 与范畴重构:康德先验哲学的批判性程序化实现
  • 电商高并发稳赢指南:ZKmall开源商城微服务架构的实战拆解
  • AI视觉重塑汽车质检,四大车间全景解析
  • Android15 GKI版本分析Kernel Crash问题
  • 金属超声波风速风向多参数一体传感器
  • NFT:Web3数字新资产
  • k230 使用摄像头将拍照的RGB565格式图片,保存为jpg图片文件到板载TF存储卡中
  • flutter 中 的 关键字
  • flutter Function和自定义的Callback有什么区别?
  • flutter 高斯模糊闪烁问题
  • Spring AI Alibaba开发实战:从入门到高级应用