前言
最近遇到了一个比较骚的需求, 难点在于在网页中, 每点一次按钮要截图并且标注出所点击的按钮.
解决思路
查找资料发现较为常见的前端截图库是 html2canvas, 暂时不清楚是否能截到 iframe 中的内容. 好消息是需求允许使用静态截图 (不考虑动态资源).
到这个时候实现起来就容易了:
- 准备好一张静态资源图 (自己电脑截一张)
- 创建 canvas 画入静态图
- btn -> click事件时获取元素的坐标 ( e.target.getBoundingClientRect() )
- 把坐标传给 canvas 在指定位置标注出来
- 把 canvas 转成 img
- 上传
实现
export default function useAutoMark(x, y, width, height) {
function createDom(name) {
return document.createElement(name)
}
function showImage(canvas) {
const image = createDom("img")
// 转为 png 格式的图片
image.src = canvas.toDataURL("image/png")
image.style.width = "100%"
document.body.appendChild(image)
}
const canvas = createDom("canvas")
const ctx = canvas.getContext("2d")
const img = new Image()
img.src = require("...") // 由于是静态图片 这里直接写死
img.onload = function() {
canvas.width = this.width
canvas.height = this.height
// 画入图片
ctx.drawImage(this, 0, 0, this.width, this.height)
// strokeRect() 方法绘制矩形(无填充)。笔触的默认颜色是黑色
// 使用 strokeStyle 属性来设置笔触的颜色、渐变或模式
ctx.strokeStyle = "#FF0000"
ctx.strokeRect(x, y, width, height)
// 开发环境在页面中展示方便调试,
if (process.env.NODE_ENV.includes("dev")) showImage(canvas)
// 图片传给后端...
}
}
btn click事件
handClick(e) {
const { left, top, width, height } = e.target.getBoundingClientRect()
useAutoMark(left - 5, top - 5, width + 10, height + 10)
}
BUG与解决方法
代码写出来后 canvas 根据坐标自动标注出来的矩形 和 图片上按钮的实际位置 有些许偏差, 于是我开始怀疑 getBoundingClientRect 获取出来的坐标不对.
查找资料并且手动计算后发现我的怀疑是多余的.
那这就很奇怪了 为什么会有偏差, 既然通过 API 获取的结果是正确的, 那问题只可能出在静态截图上.
于是, 我开始测量截图上的元素到边距的距离 大概是 128px, 而通过 API 获取的是 102px.
这就很有意思了 (128 - 102) / 102 * 100 ≈ 25%
看到这个结果, 已经知道是哪出了问题. 在 win10 上, 显示比例默认是 125%, 去设置里把它调整到 100% 后重新截图即可. ( 截完图记得把比例调回去 )