当写完本系列后,我会把源代码分享出来给大家。本课程也会持续更新与矫正。欢迎留言指正!
前面已经设计了一个底层渲染类,现在准备在这个底层类的基础上,构建一个渲染单元格的模块。
列计数器
通常在 Excel 表格中,我们会看到横向的标尺使用了:A,B,C,D之类的字母作为标记。
原理
字母的显示,一般都是使用了ASCII码进行表示的,所以,大写字母的 A-Z 是从 65 开始的,到 90 结束。
二进制 |
十进制 |
十六进制 |
缩写/字符 |
解释 |
00000000 |
0 |
00 |
NUL(null) |
空字符 |
00000001 |
1 |
01 |
SOH(start of headling) |
标题开始 |
00000010 |
2 |
02 |
STX (start of text) |
正文开始 |
00000011 |
3 |
03 |
ETX (end of text) |
正文结束 |
00000100 |
4 |
04 |
EOT (end of transmission) |
传输结束 |
00000101 |
5 |
05 |
ENQ (enquiry) |
请求 |
00000110 |
6 |
06 |
ACK (acknowledge) |
收到通知 |
00000111 |
7 |
07 |
BEL (bell) |
响铃 |
00001000 |
8 |
08 |
BS (backspace) |
退格 |
00001001 |
9 |
09 |
HT (horizontal tab) |
水平制表符 |
00001010 |
10 |
0A |
LF (NL line feed, new line) |
换行键 |
00001011 |
11 |
0B |
VT (vertical tab) |
垂直制表符 |
00001100 |
12 |
0C |
FF (NP form feed, new page) |
换页键 |
00001101 |
13 |
0D |
CR (carriage return) |
回车键 |
00001110 |
14 |
0E |
SO (shift out) |
不用切换 |
00001111 |
15 |
0F |
SI (shift in) |
启用切换 |
00010000 |
16 |
10 |
DLE (data link escape) |
数据链路转义 |
00010001 |
17 |
11 |
DC1 (device control 1) |
设备控制1 |
00010010 |
18 |
12 |
DC2 (device control 2) |
设备控制2 |
00010011 |
19 |
13 |
DC3 (device control 3) |
设备控制3 |
00010100 |
20 |
14 |
DC4 (device control 4) |
设备控制4 |
00010101 |
21 |
15 |
NAK (negative acknowledge) |
拒绝接收 |
00010110 |
22 |
16 |
SYN (synchronous idle) |
同步空闲 |
00010111 |
23 |
17 |
ETB (end of trans. block) |
传输块结束 |
00011000 |
24 |
18 |
CAN (cancel) |
取消 |
00011001 |
25 |
19 |
EM (end of medium) |
介质中断 |
00011010 |
26 |
1A |
SUB (substitute) |
替补 |
00011011 |
27 |
1B |
ESC (escape) |
溢出 |
00011100 |
28 |
1C |
FS (file separator) |
文件分割符 |
00011101 |
29 |
1D |
GS (group separator) |
分组符 |
00011110 |
30 |
1E |
RS (record separator) |
记录分离符 |
00011111 |
31 |
1F |
US (unit separator) |
单元分隔符 |
00100000 |
32 |
20 |
(space) |
空格 |
00100001 |
33 |
21 |
! |
|
00100010 |
34 |
22 |
" |
|
00100011 |
35 |
23 |
# |
|
00100100 |
36 |
24 |
$ |
|
00100101 |
37 |
25 |
% |
|
00100110 |
38 |
26 |
& |
|
00100111 |
39 |
27 |
' |
|
00101000 |
40 |
28 |
( |
|
00101001 |
41 |
29 |
) |
|
00101010 |
42 |
2A |
* |
|
00101011 |
43 |
2B |
+ |
|
00101100 |
44 |
2C |
, |
|
00101101 |
45 |
2D |
- |
|
00101110 |
46 |
2E |
. |
|
00101111 |
47 |
2F |
/ |
|
00110000 |
48 |
30 |
0 |
|
00110001 |
49 |
31 |
1 |
|
00110010 |
50 |
32 |
2 |
|
00110011 |
51 |
33 |
3 |
|
00110100 |
52 |
34 |
4 |
|
00110101 |
53 |
35 |
5 |
|
00110110 |
54 |
36 |
6 |
|
00110111 |
55 |
37 |
7 |
|
00111000 |
56 |
38 |
8 |
|
00111001 |
57 |
39 |
9 |
|
00111010 |
58 |
3A |
: |
|
00111011 |
59 |
3B |
; |
|
00111100 |
60 |
3C |
< |
|
00111101 |
61 |
3D |
= |
|
00111110 |
62 |
3E |
> |
|
00111111 |
63 |
3F |
? |
|
01000000 |
64 |
40 |
@ |
|
01000001 |
65 |
41 |
A |
|
01000010 |
66 |
42 |
B |
|
01000011 |
67 |
43 |
C |
|
01000100 |
68 |
44 |
D |
|
01000101 |
69 |
45 |
E |
|
01000110 |
70 |
46 |
F |
|
01000111 |
71 |
47 |
G |
|
01001000 |
72 |
48 |
H |
|
01001001 |
73 |
49 |
I |
|
01001010 |
74 |
4A |
J |
|
01001011 |
75 |
4B |
K |
|
01001100 |
76 |
4C |
L |
|
01001101 |
77 |
4D |
M |
|
01001110 |
78 |
4E |
N |
|
01001111 |
79 |
4F |
O |
|
01010000 |
80 |
50 |
P |
|
01010001 |
81 |
51 |
Q |
|
01010010 |
82 |
52 |
R |
|
01010011 |
83 |
53 |
S |
|
01010100 |
84 |
54 |
T |
|
01010101 |
85 |
55 |
U |
|
01010110 |
86 |
56 |
V |
|
01010111 |
87 |
57 |
W |
|
01011000 |
88 |
58 |
X |
|
01011001 |
89 |
59 |
Y |
|
01011010 |
90 |
5A |
Z |
|
01011011 |
91 |
5B |
[ |
|
01011100 |
92 |
5C |
\ |
|
01011101 |
93 |
5D |
] |
|
01011110 |
94 |
5E |
^ |
|
01011111 |
95 |
5F |
_ |
|
01100000 |
96 |
60 |
` |
|
01100001 |
97 |
61 |
a |
|
01100010 |
98 |
62 |
b |
|
01100011 |
99 |
63 |
c |
|
01100100 |
100 |
64 |
d |
|
01100101 |
101 |
65 |
e |
|
01100110 |
102 |
66 |
f |
|
01100111 |
103 |
67 |
g |
|
01101000 |
104 |
68 |
h |
|
01101001 |
105 |
69 |
i |
|
01101010 |
106 |
6A |
j |
|
01101011 |
107 |
6B |
k |
|
01101100 |
108 |
6C |
l |
|
01101101 |
109 |
6D |
m |
|
01101110 |
110 |
6E |
n |
|
01101111 |
111 |
6F |
o |
|
01110000 |
112 |
70 |
p |
|
01110001 |
113 |
71 |
q |
|
01110010 |
114 |
72 |
r |
|
01110011 |
115 |
73 |
s |
|
01110100 |
116 |
74 |
t |
|
01110101 |
117 |
75 |
u |
|
01110110 |
118 |
76 |
v |
|
01110111 |
119 |
77 |
w |
|
01111000 |
120 |
78 |
x |
|
01111001 |
121 |
79 |
y |
|
01111010 |
122 |
7A |
z |
|
01111011 |
123 |
7B |
{
|
|
01111100 |
124 |
7C |
| |
|
01111101 |
125 |
7D |
} |
|
01111110 |
126 |
7E |
~ |
|
01111111 |
127 |
7F |
DEL (delete) |
删除 |
这个就要做一个表格坐标计数器来做统计。
步进器
首先设计一个步进器:
/**
* @property {Function} excel_Row_Increase 行移动定位
* @param {String} chr 例如:A1
* @param {String} num 例如:步进
* @returns {Array} 返回字符串数组,["A","1"]
*/
excel_Row_Increase(chr,num){
this.caculate = function(chr,num){
var carry = num; // 进位标志
let temp = chr.split("");
var count = temp.length-1;
while(!(count < 0)) {
let code = this.charmap[temp[count]] + carry;
carry = 0;
if (code > 64 && code < 91){
temp[count] = String.fromCharCode(code);
}
while(code < 65){
carry--;
code = code + 26;
if(code > 64){
temp[count] = String.fromCharCode(code);
break;
}
}
while(code > 90){
carry++;
code = code - 26;
if(code < 91){
temp[count] = String.fromCharCode(code);
break;
}
}
count--;
}
var chr = temp.join("");
if(chr == "A" && carry < 0){
return {
"carry":0,
"char": chr
}
}else{
return {
"carry":carry,
"char":chr
}
}
}
var result = this.caculate(chr,num);
var ttt;
while(result["carry"]!=0){
ttt = this.caculate("A",--result["carry"]);
result["char"] = ttt["char"]+result["char"];
result["carry"] = ttt["carry"];
}
return result["char"];
}
字符的运算表
接着,使用步进器创建了一个字符的运算表,这样它就可以快速运算了。
/**
* @property {Function} setcaculatemap 创建字母运算表
* @returns {NaN} 无返回
*/
setcaculatemap(){
var begin = "A";
var mapsize = this.mapsize;
this.caculatemap = [""];
while(mapsize){
this.caculatemap.push(begin);
var begin = this.excel_Row_Increase(begin,1)
mapsize--;
}
}
源码
直接上全部代码:
/**
* 字符转编码
*/
class charcode{
/**
* 创建字符映射集
*/
constructor(){
this.charmap = {};
var ord = 65;
var ordmax = ord+26;
while(ord < ordmax){
this.charmap[String.fromCharCode(ord)] = ord;
ord++;
}
ord = 65+32;
ordmax = ord+26;
while(ord < ordmax){
this.charmap[String.fromCharCode(ord)] = ord-32;
ord++;
}
this.caculatemap = [];
this.mapsize = 20;
this.setcaculatemap();
// console.log(this.caculatemap);
this.RowColcountMap = {};
}
/**
* @property {Function} setcaculatemap 创建字母运算表
* @returns {NaN} 无返回
*/
setcaculatemap(){
var begin = "A";
var mapsize = this.mapsize;
this.caculatemap = [""];
while(mapsize){
this.caculatemap.push(begin);
var begin = this.excel_Row_Increase(begin,1)
mapsize--;
}
}
/**
* @property {Function} countelementToindex 计算坐标在单元格的位置
* @param {String} x 输入编码,表格的横向尺寸
* @param {Number} y 输入编码,表格的纵向尺寸
* @param {String} elementIndex 输入编码
* @returns {Number} 返回数字坐标
*/
countelementToindex(x,y,elementIndex){
var count = this.CharToDecimal(x); // 字符转坐标
var titlecount = count+y+1; // 标头长度
// var max = count*(y); // 表格总尺寸
var ttt = this.getRowCol(elementIndex); // 分离行列
var currentX = this.caculatemap.indexOf(ttt[0]) // 获取行的坐标
return count*(ttt[1]-1)+currentX+titlecount-1;
}
/**
* @property {Function} countindexToelement 将当前位置转化为坐标
* @param {String} x 输入编码,表格的横向尺寸
* @param {Number} y 输入编码,表格的纵向尺寸
* @param {Number} index 输入位置
* @returns {Number} 返回坐标
*/
countindexToelement(x,y,index){
var count = this.CharToDecimal(x); // 字符转坐标,获得横向的宽度
var titlecount = count+y+1; // 标头总数量
var max = count*(y); // 表格总尺寸
var A = titlecount; // 获取A的位置
var ttt = index-A+1; // 获取输入框的总个数
if(ttt >= count){
var mod = ttt%count;
if(mod != 0){
return this.caculatemap[mod]+(parseInt(ttt/count)+1)
}else{
return this.caculatemap[count]+(parseInt(ttt/count))
}
}else{
return this.caculatemap[ttt]+1
}
}
/**
* @property {Function} CHR 编码转字符
* @param {Number} ord 输入编码
* @returns {String} 返回字符编码
*/
CHR(ord){
return String.fromCharCode(ord);
}
/**
* @property {Function} ORD 字符转编码
* @param {String} chr 输入字符串
* @returns {Number} 返回字符编码
*/
ORD(chr){
return chr.charCodeAt(0);
}
/**
* @property {Function} CharToDecimal 进制字符转十进制
* @param {String} chr 输入字符串
* @returns {Number} 返回十进制编码
*/
CharToDecimal(Char){
var Decimal = this.caculatemap.indexOf(Char);
while(Decimal < 0){
this.mapsize = this.mapsize*10;
this.setcaculatemap();
Decimal = this.caculatemap.indexOf(Char);
}
return Decimal;
}
/**
* @property {Function} DecimalToChar 十进制转字符进制
* @param {Number} Decimal 输入十进制
* @returns {String} 返回字符进制
*/
DecimalToChar(Decimal){
var length = this.caculatemap.length-1;
var balance = Decimal - length;
if(balance > 0){
this.mapsize = this.mapsize+balance+1;
this.setcaculatemap();
}
return this.caculatemap[Decimal];
}
/**
* @property {Function} CharAdd 字母相加
* @param {String} CharA 输入字符
* @param {String} CharB 输入字符
* @returns {Number} 返回十进制编码
*/
CharAdd(CharA,CharB){ // 字母相加
return this.CharToDecimal(CharA)+this.CharToDecimal(CharB)
}
/**
* @property {Function} CharMinus 字母相减
* @param {String} CharA 输入字符
* @param {String} CharB 输入字符
* @returns {Number} 返回十进制编码
*/
CharMinus(CharA,CharB){ // 字母相减
return this.CharToDecimal(CharA)-this.CharToDecimal(CharB)
}
/**
* @property {Function} getRowCol 从行列串中分离出行与列
* @param {String} RC 行列串,例如:A1
* @returns {Array} 返回字符串数组,["A","1"]
*/
getRowCol(RC){
var Row = [];
var Col = [];
for(var i in RC){
this.charmap.hasOwnProperty(RC[i])?Col.push(RC[i]):Row.push(RC[i]);
}
return [Col.join(""),Row.join("")]
}
/**
* @property {Function} setRectanglecorner 设置四个坐标角落
* @param {String} a 坐标,例如:A1
* @param {String} b 坐标,例如:B2
* @returns {Array} 返回字符串数组,["A","1"]
*/
setRectanglecorner(a,b){
var RSort = [];
var CSort = [];
var aRC = this.getRowCol(a);
var bRC = this.getRowCol(b);
var Rdistance = this.CharMinus(bRC[0],aRC[0]);
if(Rdistance < 0){
RSort = [bRC[0],aRC[0]];
}else{
RSort = [aRC[0],bRC[0]];
}
if(bRC[1]-aRC[1]<0){
CSort = [bRC[1],aRC[1]];
}else{
CSort = [aRC[1],bRC[1]];
}
return [[RSort[0],CSort[0]],[RSort[1],CSort[1]]]
}
/**
* @property {Function} GetRectangle 计算出框选区域
* @param {String} from 行列串,例如:A1
* @param {String} to 行列串,例如:B2
* @returns {Array} 返回字符串数组,["A","1"]
*/
GetRectangle(from,to){
var t = this.setRectanglecorner(from,to);
var fromRC = t[0];
var toRC = t[1];
var distance =
[
this.CharMinus(toRC[0],fromRC[0]),
toRC[1]-fromRC[1]
]
// console.log(fromRC);
// console.log(toRC);
// console.log(distance);
var Rowcount = parseInt(fromRC[1])+distance[1]+1;
var ColList = this.caculatemap.slice(this.CharToDecimal(fromRC[0]),this.CharToDecimal(fromRC[0])+distance[0]+1);
var length = ColList.length;
var Rectangle = [];
for(var i = 0;i<length;i++){
for(var j = fromRC[1];j<Rowcount;j++){
Rectangle.push(ColList[i]+j);
}
}
return {
"Rowlength":Rowcount-parseInt(fromRC[1]),
"Collength":length,
"Rectangle":Rectangle
};
}
/**
* @property {Function} excel_Row_Increase 行移动定位
* @param {String} chr 例如:A1
* @param {String} num 例如:步进
* @returns {Array} 返回字符串数组,["A","1"]
*/
excel_Row_Increase(chr,num){
this.caculate = function(chr,num){
var carry = num; // 进位标志
let temp = chr.split("");
var count = temp.length-1;
while(!(count < 0)) {
let code = this.charmap[temp[count]] + carry;
carry = 0;
if (code > 64 && code < 91){
temp[count] = String.fromCharCode(code);
}
while(code < 65){
carry--;
code = code + 26;
if(code > 64){
temp[count] = String.fromCharCode(code);
break;
}
}
while(code > 90){
carry++;
code = code - 26;
if(code < 91){
temp[count] = String.fromCharCode(code);
break;
}
}
count--;
}
var chr = temp.join("");
if(chr == "A" && carry < 0){
return {
"carry":0,
"char": chr
}
}else{
return {
"carry":carry,
"char":chr
}
}
}
var result = this.caculate(chr,num);
var ttt;
while(result["carry"]!=0){
ttt = this.caculate("A",--result["carry"]);
result["char"] = ttt["char"]+result["char"];
result["carry"] = ttt["carry"];
}
return result["char"];
}
}