luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件

操作流程

  • 开关按钮:选中单元格后右键,下拉框选择“开关按钮”,输入选择和未选择的值,点击确定,就会在该单元格下生成开关按钮,之后点击单元格就能切换值了。操作流程见下图: 

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第1张图片

  • 单选框:同上选中单选框,数据各个数据值用英文逗号分割,点击确定后会在单元格中生成单选框(默认选中第一个),之后点击文字切换单元格的值。操作如下:

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第2张图片

  • 复选框:同上。

实现思路

开关按钮

1、确定数据结构。

luckysheet中一个单元格含有数据验证时,会将数据验证信息存储在dataVerification对象中,对象的key是由单元格行列坐标用“_”拼接而成,开关按钮中value1就是选中时的值,value2就是取消时的值,点击单元格切换值的时候就会读取这两个值,并且“checked”字段也会跟着切换。

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第3张图片

2、canvas画画

        在draw.js文件中,luckysheet之前画文字时是有提供一个绘画坐标的(horizonAlignPos,verticalAlignPos_text),这个变量就是参考点。先把未选中状态的图像画好,之后根据是否选中再决定是否画选中状态的图像

单选框

1、确定数据结构。

用value字段(数组)存储之前input框中输入的值,checked字段(数组,并且只有一个为true)代表对应的value是否勾选,textWidth存储的每一个值当前选项和之前所有选项文字的累加,reginAreaArr则是存储每个选项的范围(之后要判断鼠标点击在哪个选项所属的区域)。【其他字段无关紧要】

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第4张图片

2、canvas画画

        遍历checked数组后先画大圆,之后画小圆,选中状态的话就颜色是蓝色的。最后遍历value填充文字。后续圆圈的坐标就利用textWidth把前面的文字宽和圆圈宽加清楚就行。

复选框

        具体操作同单选框、只是圆圈变为方块。

问题

1、如何确定鼠标点击在单选框的选项上?

        首先是要确定鼠标相对于画布原点的坐标curClickCoord,然后用这个坐标与之前存储的reginAreaArr中的每一项作对比,判定选中就更新视图和相关的数据。

        得到curClickCoord代码如下:

    // nby 第一步存储点击坐标 
        let canvasClickX = event.clientX;   //鼠标相对于视口左边的距离
        var canvasClickY = event.clientY;
        let rect = luckysheetTableContent.canvas.getBoundingClientRect(); //能得到dom相对于视口各边的距离

        canvasClickX -= rect.left;  
        canvasClickY -= rect.top;
        // nby 当前鼠标点击位置,相对于canvas
        Store.curClickCoord = {x:canvasClickX,y:canvasClickY}

      event.clientX和event.clientY分别是鼠标点击相对于浏览器视口的X、Y坐标  canvasDom.getBoundingClientRect().left和top则是能获取当前canvas画布相对于浏览器视口的左右距离,两者相减就是鼠标相对于画布的坐标。【1、不用offsetLeft是因为画布祖先节点有用position,这样就不是相对于body的偏移;2、不直接用offsetX是因为源码中鼠标点击没有绑定到canvas上,而是监听画布上层的div,改起来麻烦(这也是offsetX的局限性)。3、不要用pageX代替clientX,pageX是相对于文档,在画布超出有滚动条时,pageX不准】

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第5张图片

2、canvas中咋获取文字宽的?

        有measureText这个api能得到文字的宽,luckysheet中也封装了自己的方法getMeasureText用以适配不同字体下的文字宽,所以我用的luckysheet封装好的。

context.measureText(text).width;

4、除了这种点击流程,有想过其他的办法吗?

        之前考虑过双击单元格后弹出radio标签,通过获取点击后的值再来改变单元格的值,这样做的目的是绕开canvas(当时不确定利用canvas是否可行),我按照这个思路写了一部分发现也挺麻烦的,并且产品经理坚持要类似直接点击radio标签的效果,所以最终就采用的画canvas的方法。利用canvas去画radio的方法实现的效果用户操作更简洁、更直观。

        最后附上三个的效果图:

luvkysheet中利用canvas新添加开关按钮、单选框、复选框等控件_第6张图片

代码地址

由于代码量比较多,直接贴git地址

表格编辑器的luckysheet: 工企表格编辑器的luckysheet (gitee.com)

你可能感兴趣的:(luckysheet,前端,javascript)