答题卡生成与打印,HTML内容转图片下载

前言

前文说了如何识别答题卡,本文来说说怎么生成答题卡。

OpenCV可以用来生成,但是文字换行等场景就比较难实现,这里使用HTML生成答题卡。

A3/A4尺寸

A4 210mm×297mm

A3 420mm×297mm

HTML转Canvas

https://www.psvmc.cn/article/2022-06-21-html-canvas-pdf.html

获取DIV坐标

绝对位置

网页元素的绝对位置,指该元素的左上角相对于整张网页左上角的坐标

首先,每个元素都有offsetTop和offsetLeft属性,表示该元素的左上角与父容器(offsetParent对象)左上角的距离。所以,只需要将这两个值进行累加,就可以得到该元素的绝对坐标。但这里要注意一个问题:要考虑offsetParent的border的宽度。

方式1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 得到对象的相对浏览器的坐标
export function getObjPos(_target) {
var target = _target;
var pos = {
x: target.offsetLeft,
y: target.offsetTop
};

target = target.offsetParent;
while (target) {
pos.x += target.offsetLeft + target.clientLeft;
pos.y += target.offsetTop + target.clientTop;

target = target.offsetParent
}
return pos;
}

注意

一定要添加父元素的Border的宽度(clientLeft)。

隐藏的元素要用opacity: 0;,不能用display: none;,否则获取不了位置。

这种方式不是特别精确,如果dom的宽高不是整数的时候会出现偏差。

运算效率也相对较低。

方式2

这种方式要注意滚动条所在的DOM是那个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export function getObjPos(_target, scroll_dom) {
var rect = _target.getBoundingClientRect();
var pos = {
x: rect.left,
y: rect.top
};
var scrollLeft = 0;
var scrollTop = 0;
if (scroll_dom) {
scrollLeft = scroll_dom.scrollLeft;
scrollTop = scroll_dom.scrollTop;
} else {
scrollLeft =
document.body.scrollLeft || document.documentElement.scrollLeft;
scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
}

pos.x += scrollLeft;
pos.y += scrollTop;
return pos;
}

注意

隐藏的元素要用opacity: 0;,不能用display: none;,否则获取不了位置。

运算效率相对高点。

相对位置

网页元素的相对位置,指该元素左上角相对于浏览器窗口左上角的坐标

方法1

获取元素的相对位置,JS还提供了一种更简单的方法:Element.getBoundingClientRect()

Element.getBoundingClientRect()返回一个对象,对象包含了元素距离窗口的位置属性:left、right、top、bottom

1
2
3
let odiv = document.querySelector(".div2");
console.info(odiv.getBoundingClientRect().left);
console.info(odiv.getBoundingClientRect().top);

方法2

有了绝对位置以后,获得相对位置就很容易了,只要将绝对坐标减去页面的滚动条滚动的距离就可以了。

1
2
3
4
5
6
7
8
function getObjPosR (element) {
let pos = getObjPos2(element);
var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
pos.x -= scrollLeft;
pos.y -= scrollTop;
return pos;
}

PX和MM互转

方式1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function unitUtil () {
var pxWidth = 0;
var tmpNode = document.createElement("DIV");
tmpNode.style.cssText = "width:1mm;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
document.body.appendChild(tmpNode);
pxWidth = tmpNode.getBoundingClientRect().width.toFixed(2);
tmpNode.parentNode.removeChild(tmpNode);

this.mm2px = function (mm) {
return parseFloat((mm * pxWidth).toFixed(2));
}

this.px2mm = function (px) {
return parseFloat((px / pxWidth).toFixed(2));
}
}

调用

1
new unitUtil().px2mm(width)

方式2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function unitConversion () {
/**
* 获取DPI
* @returns {Array}
*/
this.getDPI = function () {
var arrDPI = new Array();
if (window.screen.deviceXDPI != undefined) {
arrDPI[0] = window.screen.deviceXDPI;
arrDPI[1] = window.screen.deviceYDPI;
}
else {
var tmpNode = document.createElement("DIV");
tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
document.body.appendChild(tmpNode);
arrDPI[0] = parseInt(tmpNode.offsetWidth);
arrDPI[1] = parseInt(tmpNode.offsetHeight);
tmpNode.parentNode.removeChild(tmpNode);
}
return arrDPI;
};
/**
* px转换为mm
* @param value
* @returns {number}
*/
this.px2mm = function (value) {
var inch = value / this.getDPI()[0];
var c_value = inch * 25.4;
return c_value;
};

/**
* mm转换为px
* @param value
* @returns {number}
*/
this.mm2px = function (value) {
var inch = value / 25.4;
var c_value = inch * this.conversion_getDPI()[0];
return c_value;
}
}

调用

1
2
new unitConversion().px2mm(width)
new unitConversion().mm2px(width)