Skip to main content

口算拍批

· 2 min read
wang bo
早睡早起

目标 🎯:图书频道新增口算拍照批改功能,用户进入图书频道可以批改口算试题,给出批改结果和答案;

拍批流程#

  1. 打开客户端拍照页,等待拍好的照片回调
    1. 参数 photoId、path
  2. 将 base64 的照片转成 formData 格式,传给后端进行批改
    1. 判断拍批是否成功、以及有无剩余次数
  3. 后端返回批改结果,再处理结果
    1. 判断此次拍批是否过期
    2. 如果拍批成功跳转 拍批结果页

结果页#

需求 1: 我们需要圈出来错题 ❌、或者给对的题后面打对勾 ✅#

归一化: 目标检测中,为了方便记录数据格式,将图形坐标的 x、y 归一化到 0-1

# bbox -> feature map,把bbox的全局坐标系转换成相对于他所在的局部坐标系,左上角为原点。
bbox: [0.25229, 0.30104, 0.2806, 0.30161, 0.27748, 0.38805, 0.24917, 0.38748]left: bbox[0]top: bbox[1]width: bbox[2]-bbox[0]height: bbox[7]-bbox[1]

but! 用户拍出来的照片不可能都是水平的,所以需要前端转先转成从左向右,自上而下坐标系后,再旋转一个角度 >

需求 2: 点击错题 显示答案时 页面平滑的滚动 😴#

点击错题的红圈后,交互中的滚动顺序#

  1. 错题信息弹出层 弹出 (~ 0.3s)
  2. popup 中错题列表滚到选择的题目 (通过自定义 observer 观察)改变 observerStatus 为 true,通知后续滚动任务
  3. 背景图中红圈滚动到可视范围 改 observerStatus 为 false

为什么要设置个顺序?

  • 在 ios 中滚动可以 3 个一起进行滚动
  • 在 pc 和 andriod 中 后续滚动任务 会中断 前置滚动任务(导致第二步只滚动一部分,没有滚动到期待的位置)
  • 所以使用的顺序滚动,第一步滚动结束(0.3s)、执行第二步滚动(通过自定义观察者观察 element 是否滚动到页面中)、再执行第三步

为什么自定义观察者,而不去用 Intersection Observer API

  • IntersectionObserver ios 兼容性不好 只支持到 12.1+,所以自定义观察者(customObserver)
# 错题数字的滚动let ele = document.getElementById('hover')
const orientationHover = (ele: HTMLElement) => {    ele.scrollIntoView({        behavior: 'smooth',        inline: 'center',    })    customObserver(ele)}
const customObserver = (ele: HTMLElement) => {    requestAnimationFrame(() => {        if (ele.getBoundingClientRect().x > 0 && ele.getBoundingClientRect().x < window.innerWidth) {            console.log('滑到了屏幕中~')            setObserverStatus(true)        } else {            customObserver(ele)        }    })}
useEffect(() => {    if (ele) {      orientationHover(ele)    }}, [ele])
# 背景的滚动 useEffect(() => {    if (observerStatus && pcrBg.current) {        pcrBg.scrollTo({            top: errItem.bbox[1] * questionImage.height - pcrBg.clientHeight / 2,            behavior: 'smooth',        })        setObserverStatus(false)    }}, [observerStatus])