From 5d572676d46692719309c20e536d001ccfe2cd2f Mon Sep 17 00:00:00 2001 From: javahuang Date: Tue, 8 Sep 2020 15:17:52 +0800 Subject: [PATCH 01/19] fix(bugs): fix issue #27 #29 --- src/controllers/formulaBar.js | 4 ++++ src/controllers/handler.js | 2 +- src/controllers/keyboard.js | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controllers/formulaBar.js b/src/controllers/formulaBar.js index b2c5aa2..2919942 100644 --- a/src/controllers/formulaBar.js +++ b/src/controllers/formulaBar.js @@ -33,6 +33,10 @@ export function formulaBarInitial(){ let row_index = last["row_focus"], col_index = last["column_focus"]; + let $input = $("#luckysheet-rich-text-editor"),value = $input.text(); + if(value) { + formula.updatecell(row_index, col_index); + } luckysheetupdateCell(row_index, col_index, Store.flowdata, null, true); formula.rangeResizeTo = $("#luckysheet-functionbox-cell"); } diff --git a/src/controllers/handler.js b/src/controllers/handler.js index a4c7fc4..0ff6f83 100644 --- a/src/controllers/handler.js +++ b/src/controllers/handler.js @@ -4580,7 +4580,7 @@ export default function luckysheetHandler() { } } - let fs = Math.floor(parseInt($td.css("font-size")) * 72 / dpi_y) + 1; + let fs = Math.floor(parseInt($td.css("font-size")) * 72 / 96) + 1; cell.fs = fs; let fc = $td.css("color"); diff --git a/src/controllers/keyboard.js b/src/controllers/keyboard.js index 8a334ed..4db7733 100644 --- a/src/controllers/keyboard.js +++ b/src/controllers/keyboard.js @@ -834,7 +834,7 @@ export function keyboardInitial(){ else if (kcode == keycode.RIGHT && parseInt($inputbox.css("top")) > 0) { formulaMoveEvent("right", ctrlKey, shiftKey); } - else if (!((kcode >= 112 && kcode <= 123) || kcode <= 46 || kcode == 144 || kcode == 108 || event.ctrlKey || event.altKey || (event.shiftKey && (kcode == 37 || kcode == 38 || kcode == 39 || kcode == 40))) || kcode == 8 || kcode == 32 || kcode == 46 || (event.ctrlKey && kcode == 86)) { + else if (!((kcode >= 112 && kcode <= 123) || kcode <= 46 || kcode == 144 || kcode == 108 || event.ctrlKey || event.altKey || (event.shiftKey && (kcode == 37 || kcode == 38 || kcode == 39 || kcode == 40 || kcode == keycode.WIN || kcode == keycode.WIN_R || kcode == keycode.MENU))) || kcode == 8 || kcode == 32 || kcode == 46 || (event.ctrlKey && kcode == 86)) { formula.functionInputHanddler($("#luckysheet-functionbox-cell"), $("#luckysheet-rich-text-editor"), kcode); setCenterInputPosition(Store.luckysheetCellUpdate[0], Store.luckysheetCellUpdate[1], Store.flowdata); } From d52d33eb2538c3dd500fb4c39c5789ce13b786f5 Mon Sep 17 00:00:00 2001 From: danny <692763892@qq.com> Date: Tue, 8 Sep 2020 19:59:46 +0800 Subject: [PATCH 02/19] danny first commit --- docs/guide/data.md | 6 +- docs/guide/sheet.md | 1346 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1349 insertions(+), 3 deletions(-) create mode 100644 docs/guide/sheet.md diff --git a/docs/guide/data.md b/docs/guide/data.md index 9774abf..663cb89 100644 --- a/docs/guide/data.md +++ b/docs/guide/data.md @@ -29,15 +29,15 @@ "colhidden":{}, //hidden columns "borderInfo":{}, //borders }, - "celldata": [], //initialize the cell data used - "data": [], //Update and store the cell data used + "celldata": [], //initialize the cell data + "data": [], //Update and store the cell data "scrollLeft": 0, //Left and right scroll bar position "scrollTop": 315, //Up and down scroll bar position "luckysheet_select_save": [], //selected area "luckysheet_conditionformat_save": {},//Conditional format "calcChain": [],//Formula chain "isPivotTable":false,//Whether to pivot table - "pivotTable":{},//Pivot table settings + "pivotTable":{},//Pivot table configuration "filter_select": null,//Filter range "filter": null,//Filter configuration "luckysheet_alternateformat_save": [], //Alternate colors diff --git a/docs/guide/sheet.md b/docs/guide/sheet.md new file mode 100644 index 0000000..1dda39b --- /dev/null +++ b/docs/guide/sheet.md @@ -0,0 +1,1346 @@ +# Sheet Configuration + +## Initial +if you want to initial the `options`, you need to arrange every sheet data to `options.data` + +> when the initialization is done, you can use [`luckysheet.getAllSheets()`](/zh/guide/api.html#getAllSheets([setting])) to get all working sheet configurations. + +eg: options.data: +```json +[ + { + "name": "Cell", //Worksheet name + "color": "", //Worksheet color + "index": 0, //Worksheet index + "status": 1, //Worksheet active status + "order": 0, //The order of the worksheet + "hide": 0,//Whether worksheet hide + "row": 36, //the number of rows in a sheet + "column": 18, //the number of columns in a sheet + "celldata": [], //Initial the cell data + "config": { + "merge":{}, //merged cells + "rowlen":{}, //Table row height + "columnlen":{}, //Table column width + "rowhidden":{}, //hidden rows + "colhidden":{}, //hidden columns + "borderInfo":{}, //borders + }, + "scrollLeft": 0, //Left and right scroll bar position + "scrollTop": 315, //Up and down scroll bar position + "luckysheet_select_save": [], //selected area + "calcChain": [],//Formula chain + "isPivotTable":false,//Whether is pivot table + "pivotTable":{},//Pivot table settings + "filter_select": {},//Filter range + "filter": null,//Filter configuration + "luckysheet_alternateformat_save": [], //Alternate colors + "luckysheet_alternateformat_save_modelCustom": [], //Customize alternate colors + "luckysheet_conditionformat_save": {},//condition format + "frozen": {}, //freeze row and column configuration + "chart": [], //Chart configuration + "allowEdit": true, //is editble + "zoomRatio":1, // zoom ratio + }, + { + "name": "Sheet2", + "color": "", + "index": 1, + "status": 0, + "order": 1, + "celldata": [], + "config": {} + }, + { + "name": "Sheet3", + "color": "", + "index": 2, + "status": 0, + "order": 2, + "celldata": [], + "config": {}, + } +] +``` + +### name +- 类型:String +- 默认值:"Sheet1" +- 作用:工作表名称 + +------------ +### color +- 类型:String +- 默认值:"##f20e0e" +- 作用:工作表颜色,工作表名称下方会有一条底部边框 + +------------ +### index +- 类型:Number +- 默认值:0 +- 作用:工作表索引,从0开始 + +------------ +### status +- 类型:Number +- 默认值:1 +- 作用: 激活状态,仅有一个激活状态的工作表,其他工作表为 0 + +------------ +### order +- 类型:Number +- 默认值:0 +- 作用: 工作表的索引,新增工作表时会递增,从0开始 + +------------ +### hide +- 类型:Number +- 默认值:0 +- 作用: 是否隐藏,`0`为不隐藏,`1`为隐藏 + +------------ +### row +- 类型:Number +- 默认值:36 +- 作用: 单元格行数 + +------------ +### column +- 类型:Number +- 默认值:18 +- 作用: 单元格列数 + +------------ +### celldata +- 类型:Array +- 默认值:[] +- 作用: 原始单元格数据集,存储sheet中所有单元格中的值,是一个包含`{r:0,c:0,v:{m:"value",v:"value",ct: {fa: "General", t: "g"}}}`格式单元格信息的一维数组,只在初始化的时候使用。 + + r代表行,c代表列,v代表该单元格的值,值可以是字符、数字或者对象。 + + Luckysheet在建立的时候会根据 `options.data[i].row` 和 `options.data[i].column` 的行列数量大小新建一个表格data,然后再使用 `data[r][c]=v` 的方式填充表格数据,空数据单元格以null表示。 + + 使用celldata初始化完表格后,数据转换为luckysheetfile中的字段[data](#data),如`luckysheetfile[i].data`,后续操作表格的数据更新,会更新到这个data字段中,celldata不再使用。 + +- 示例: + ```js + [{ + "r": 0, + "c": 0, + "v": { + ct: {fa: "General", t: "g"}, + m:"value1", + v:"value1" + } + }, { + "r": 0, + "c": 1, + "v": { + ct: {fa: "General", t: "g"}, + m:"value2", + v:"value2" + } + }] + ``` +> 详细了解 [单元格格式](/zh/guide/cell.html) + +------------ +### config +- 类型:Object +- 默认值:{} +- 作用:表格行高、列宽、合并单元格、边框、隐藏行等设置 + + 注意,config如果为空,必须为空对象`{}`,不能为字符串或者null + +#### config.merge +- 类型:Object +- 默认值:{} +- 作用:合并单元格设置 +- 示例: + ```js + { + "13_5": { + "r": 13, + "c": 5, + "rs": 3, + "cs": 1 + }, + "13_7": { + "r": 13, + "c": 7, + "rs": 3, + "cs": 2 + }, + "14_2": { + "r": 14, + "c": 2, + "rs": 1, + "cs": 2 + } + } + ``` + 对象中的`key`为`r + '_' + c`的拼接值,`value`为左上角单元格信息: r:行数,c:列数,rs:合并的行数,cs:合并的列数 + +#### config.rowlen +- 类型:Object +- 默认值:{} +- 作用:每个单元格的行高 +- 示例: + ```js + "rowlen": { + "0": 20, + "1": 20, + "2": 20 + } + ``` + +#### config.columnlen +- 类型:Object +- 默认值:{} +- 作用:每个单元格的列宽 +- 示例: + ```js + "columnlen": { + "0": 97, + "1": 115, + "2": 128 + } + ``` + +#### config.rowhidden +- 类型:Object +- 默认值:{} +- 作用:隐藏行信息,格式为:`rowhidden[行数]: 0`, + + `key`指定行数即可,`value`总是为`0` +- 示例: + ```js + "rowhidden": { + "30": 0, + "31": 0 + } + ``` + +#### config.colhidden +- 类型:Object +- 默认值:{} +- 作用:隐藏列 + 格式为:`colhidden[列数]: 0`, + + `key`指定列数即可,`value`总是为`0` +- 示例: + ```js + "colhidden": { + "30": 0, + "31": 0 + } + ``` + +#### config.borderInfo +- 类型:Object +- 默认值:{} +- 作用:单元格的边框信息 +- 示例: + ```js + "borderInfo": [{ + "rangeType": "cell", + "value": { + "row_index": 3, + "col_index": 3, + "l": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "r": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "t": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "b": { + "style": 10, + "color": "rgb(255, 0, 0)" + } + } + }, + { + "rangeType": "range", + "borderType": "border-all", + "style": "3", + "color": "#0000ff", + "range": [{ + "row": [7, 8], + "column": [2, 3] + }] + }, { + "rangeType": "range", + "borderType": "border-inside", + "style": "3", + "color": "#0000ff", + "range": [{ + "row": [7, 8], + "column": [8, 9] + }] + }] + ``` + 范围类型分单个单元格和选区两种情况 + 1. 选区 `rangeType: "range"` + + + 边框类型 `borderType:"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none"`, + + 边框粗细 `style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` + + 边框颜色 `color: 16进制颜色值` + + 选区范围 `range: 行列信息数组` + + 2. 单个单元格 `rangeType:"cell"` + + 单元格的行数和列数索引 `value.row_index: 数字,value.col_index: 数字` + + 四个边框对象 `value.l:左边框,value.r:右边框,value.t:上边框,value.b:下边框` + + 边框粗细 `value.l.style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` + + 边框颜色 `value.l.color: 16进制颜色值` + + 更多模板: + + + ```js + { + "rangeType": "range", + "borderType": "border-all", + "style": "3", + "color": "#0000ff", + "range": [{ + "row": [7, 8], + "column": [2, 3] + }] + } + ``` + 表示设置范围为`{"row": [7, 8],"column": [2, 3]}`的选区,类型为所有边框,边框粗细为`Dotted`,颜色为`"#0000ff"` + + + ```js + { + "rangeType": "cell", + "value": { + "row_index": 3, + "col_index": 3, + "l": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "r": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "t": { + "style": 10, + "color": "rgb(255, 0, 0)" + }, + "b": { + "style": 10, + "color": "rgb(255, 0, 0)" + } + } + } + ``` + 表示设置单元格`"D4"`,上边框/下边框/左边框/右边框都是边框粗细为`"MediumDashDot"`,颜色为`"rgb(255, 0, 0)"` + +------------ +### scrollLeft +- 类型:Number +- 默认值:0 +- 作用: 左右滚动条位置 + +------------ +### scrollTop +- 类型:Number +- 默认值:0 +- 作用: 上下滚动条位置 + +------------ +### luckysheet_select_save +- 类型:Array +- 默认值:[] +- 作用: 选中的区域,支持多选,是一个包含多个选区对象的一维数组 +- 示例: + ```js + [ + { + "row": [ 0, 1 ], + "column": [ 0, 0 ] + }, + { + "row": [ 3, 4 ], + "column": [ 1, 2 ] + }, + { + "row": [ 1, 3 ], + "column": [ 3, 3 ] + } + ] + ``` + +------------ +### calcChain +- 类型:Array +- 默认值:[] +- 作用: 公式链,用于公式所链接的单元格改变后,所有引用此单元格的公式都会联动刷新 +- 示例: + ```js + [{ + "r": 6, //行数 + "c": 3, //列数 + "index": 1, //工作表id + "func": [true, 23.75, "=AVERAGE(D3:D6)"], //公式信息,包含公式计算结果和公式字符串 + "color": "w", //"w":采用深度优先算法 "b":普通计算 + "parent": null, + "chidren": {}, + "times": 0 + }, { + "r": 7, + "c": 3, + "index": 1, + "func": [true, 30, "=MAX(D3:D6)"], + "color": "w", + "parent": null, + "chidren": {}, + "times": 0 + }] + ``` + +------------ +### isPivotTable +- 类型:Boolean +- 默认值:false +- 作用: 是否数据透视表 + +------------ +### pivotTable +- 类型:Object +- 默认值:{} +- 作用: 数据透视表设置 +- 示例: + ```js + { + "pivot_select_save": { + "row": [0, 12], + "column": [0, 4] + }, + "pivotDataSheetIndex": 6, //源数据所在的sheet页 + "column": [{ + "index": 3, + "name": "subject", + "fullname": "subject" + }], + "row": [{ + "index": 1, + "name": "student", + "fullname": "student" + }], + "filter": [], + "values": [{ + "index": 4, + "name": "score", + "fullname": "count:score", + "sumtype": "COUNTA", + "nameindex": 0 + }], + "showType": "column", + "pivotDatas": [ //数据透视表的源数据 + ["count:score", "science", "mathematics", "foreign language", "English", "total"], + ["Alex", 1, 1, 1, 1, 4], + ["Joy", 1, 1, 1, 1, 4], + ["Tim", 1, 1, 1, 1, 4], + ["total", 3, 3, 3, 3, 12] + ], + "drawPivotTable": false, + "pivotTableBoundary": [5, 6] + } + ``` + +------------ +### filter_select +- 类型:Object +- 默认值:{} +- 作用: 筛选范围,一个选区,一个sheet只有一个筛选范围,类似`luckysheet_select_save` +- 示例: + ```js + { + + "row": [ 2, 6 ], + "column": [ 1, 3 ] + } + ``` + +------------ +### filter +- 类型:Object +- 默认值:{} +- 作用: 筛选的具体设置 +- 示例: + ```js + { + "0": { + "caljs": { // 条件筛选类型 + "value": "cellnull", + "text": "Is empty", + "type": "0" + }, + "rowhidden": { "3": 0, "4": 0 }, // 隐藏行 + "optionstate": true, //是否开启配置 + "str": 2, // 范围,起始行 + "edr": 6, // 范围,结束行 + "cindex": 1, // 当前范围列索引 + "stc": 1, // 范围,起始列 + "edc": 3 // 范围,结束列 + }, + "1": { + "caljs": {}, + "rowhidden": { "6": 0 }, + "optionstate": true, + "str": 2, + "edr": 6, + "cindex": 2, + "stc": 1, + "edc": 3 + } + } + ``` + +------------ +### luckysheet_alternateformat_save +- 类型:Array +- 默认值:[] +- 作用: 交替颜色配置 +- 示例: + ```js + [{ + "cellrange": { //单元格范围 + "row": [1, 6], + "column": [1, 5] + }, + "format": { + "head": { //页眉颜色 + "fc": "#000", + "bc": "#5ed593" + }, + "one": { //第一种颜色 + "fc": "#000", + "bc": "#ffffff" + }, + "two": { //第二种颜色 + "fc": "#000", + "bc": "#e5fbee" + }, + "foot": { //页脚颜色 + "fc": "#000", + "bc": "#a5efcc" + } + }, + "hasRowHeader": false, //含有页眉 + "hasRowFooter": false //含有页脚 + }, { + "cellrange": { + "row": [1, 6], + "column": [8, 12] + }, + "format": { + "head": { + "fc": "#000", + "bc": "#5599fc" + }, + "one": { + "fc": "#000", + "bc": "#ffffff" + }, + "two": { + "fc": "#000", + "bc": "#ecf2fe" + }, + "foot": { + "fc": "#000", + "bc": "#afcbfa" + } + }, + "hasRowHeader": false, + "hasRowFooter": false + }] + ``` + +------------ +### luckysheet_alternateformat_save_modelCustom +- 类型:Array +- 默认值:[] +- 作用:自定义交替颜色,包含多个自定义交替颜色的配置 +- 示例: + ```js + [{ + "head": { //页眉颜色 + "fc": "#6aa84f", + "bc": "#ffffff" + }, + "one": { //第一种颜色 + "fc": "#000", + "bc": "#ffffff" + }, + "two": { //第二种颜色 + "fc": "#000", + "bc": "#e5fbee" + }, + "foot": { //页脚颜色 + "fc": "#000", + "bc": "#a5efcc" + } + }] + ``` + +------------ +### luckysheet_conditionformat_save +- 类型:Array +- 默认值:[] +- 作用: 条件格式配置信息,包含多个条件格式配置对象的一维数组, + + type: "default": 突出显示单元格规则和项目选区规则, + + "dataBar":数据条, + + "icons":图标集, + + "colorGradation": 色阶 + + API中对此设置也有介绍[API setRangeConditionalFormat](/zh/guide/api.html) +- 示例: + ```js + [ + { + "type": "default", + "cellrange": [ //应用的范围 + { + "row": [ 2, 7 ], + "column": [ 2, 2 ] + } + ], + "format": { //type 为 default 时 应设置文本颜色和单元格颜色 + "textColor": "#000000", + "cellColor": "#ff0000" + }, + "conditionName": "betweenness", //类型 + "conditionRange": [ //条件值所在单元格 + { + "row": [ 4, 4 ], + "column": [ 2, 2 ] + }, + { + "row": [ 6, 6 ], + "column": [ 2, 2 ] + } + ], + "conditionValue": [ 2, 4 + ] //自定义传入的条件值 + }, + { + "type": "dataBar", + "cellrange": [ + { + "row": [ 10, 15 ], + "column": [ 10, 11 ] + } + ], + "format": [ + "#6aa84f", + "#ffffff" + ] + }, + { + "type": "icons", + "cellrange": [ + { + "row": [ 19, 23 ], + "column": [ 2, 2 ] + } + ], + "format": { + "len": "3", + "leftMin": "0", + "top": "0" + } + }, + { + "type": "colorGradation", + "cellrange": [ + { + "row": [ 10, 15 ], + "column": [ 6, 6 ] + } + ], + "format": [ + "rgb(99, 190, 123)", + "rgb(255, 235, 132)", + "rgb(248, 105, 107)" + ] + } + ] + ``` + +------------ +### frozen +- 类型:Array +- 默认值:[] +- 作用: 冻结行列设置,分为6种类型 + 1. "row": 冻结首行 + 2. "column": 冻结首列 + 3. "both": 冻结行列 + 4. "rangeRow": 冻结行到选区 + 5. "rangeColumn": 冻结列到选区 + 6. "rangeBoth": 冻结行列到选区 + 7. "cancel": 取消冻结 + + 当设置冻结到选区的时候,需要设置开启冻结的单元格位置,格式为`{ row_focus:0, column_focus:0 }`,意为当前激活的单元格的行数和列数。 + + sheet新的配置属性,存储更语义化的配置,用于初始化和传给后端。 + + 注意一点,luckysheetfile中还有一个配置freezen,其中的freezenhorizontaldata仍然用作本地数据,但是不发给后台存储,只做本地调试。 + +- 示例: + - 冻结首行 + ```json + { + type: 'row' + } + ``` + - 冻结行到`'A1'`选区 + ```json + { + type: 'rangeRow', + range: {row_focus: 0, column_focus: 0} + } + ``` + - 冻结行列到`'B2'`选区 + ```json + { + type: 'rangeBoth', + range: {row_focus: 1, column_focus: 1} + } + ``` + +------------ +### chart +- 类型:Array +- 默认值:[] +- 作用: 图表配置,参照chartMix的配置格式,允许只设置想要的图表属性,一个完整的配置案例如下。 +- 示例: + :::::: details + ```json + { + "chart_id": "chart_p145W6i73otw_1596209943446", + "width": 400, + "height": 250, + "left": 20, + "top": 120, + "sheetIndex": "Sheet_6az6nei65t1i_1596209937084", + "needRangeShow": true, + "chartOptions": { + "chart_id": "chart_p145W6i73otw_1596209943446", + "chartAllType": "echarts|line|default", + "rangeArray": [ { "row": [ 0, 4 ], "column": [ 0, 7 ] } ], + "rangeColCheck": { "exits": true, "range": [ 0, 0 ] }, + "rangeRowCheck": { "exits": true, "range": [ 0, 0 ] }, + "rangeConfigCheck": false, + "defaultOption": { + "title": { + "show": false, + "text": "默认标题", + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "position": { + "value": "left-top", + "offsetX": 40, + "offsetY": 50 + } + }, + "subtitle": { + "show": false, + "text": "", + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "distance": { + "value": "auto", + "cusGap": 40 + } + }, + "config": { + "color": "transparent", + "fontFamily": "Sans-serif", + "grid": { + "value": "normal", + "top": 5, + "left": 10, + "right": 20, + "bottom": 10 + } + }, + "legend": { + "show": true, + "selectMode": "multiple", + "selected": [ + { + "seriesName": "衣服", + "isShow": true + }, + { + "seriesName": "食材", + "isShow": true + }, + { + "seriesName": "图书", + "isShow": true + } + ], + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "position": { + "value": "left-top", + "offsetX": 40, + "offsetY": 50, + "direction": "horizontal" + }, + "width": { + "value": "auto", + "cusSize": 25 + }, + "height": { + "value": "auto", + "cusSize": 14 + }, + "distance": { + "value": "auto", + "cusGap": 10 + }, + "itemGap": 10, + "data": [ + "Mon", + "Tues", + "Wed", + "Thur", + "Fri", + "Sat", + "Sun" + ] + }, + "tooltip": { + "show": true, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "backgroundColor": "rgba(50,50,50,0.7)", + "triggerOn": "mousemove", + "triggerType": "item", + "axisPointer": { + "type": "line", + "style": { + "color": "#555", + "width": "normal", + "type": "solid" + } + }, + "format": [ + { + "seriesName": "衣服", + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto" + }, + { + "seriesName": "食材", + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto" + }, + { + "seriesName": "图书", + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto" + } + ], + "position": "auto" + }, + "axis": { + "axisType": "xAxisDown", + "xAxisUp": { + "show": false, + "title": { + "showTitle": false, + "text": "", + "nameGap": 15, + "rotate": 0, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "fzPosition": "end" + }, + "name": "显示X轴", + "inverse": false, + "tickLine": { + "show": true, + "width": 1, + "color": "auto" + }, + "tick": { + "show": true, + "position": "outside", + "length": 5, + "width": 1, + "color": "auto" + }, + "tickLabel": { + "show": true, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "rotate": 0, + "prefix": "", + "suffix": "", + "optimize": 0, + "distance": 0, + "min": "auto", + "max": "auto", + "ratio": 1, + "digit": "auto" + }, + "netLine": { + "show": false, + "width": 1, + "type": "solid", + "color": "auto", + "interval": { + "value": "auto", + "cusNumber": 0 + } + }, + "netArea": { + "show": false, + "interval": { + "value": "auto", + "cusNumber": 0 + }, + "colorOne": "auto", + "colorTwo": "auto" + }, + "axisLine": { + "onZero": false + } + }, + "xAxisDown": { + "show": true, + "title": { + "showTitle": false, + "text": "", + "nameGap": 15, + "rotate": 0, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "fzPosition": "end" + }, + "name": "显示X轴", + "inverse": false, + "tickLine": { + "show": true, + "width": 1, + "color": "auto" + }, + "tick": { + "show": true, + "position": "outside", + "length": 5, + "width": 1, + "color": "auto" + }, + "tickLabel": { + "show": true, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "rotate": 0, + "prefix": "", + "suffix": "", + "optimize": 0, + "distance": 0, + "min": null, + "max": null, + "ratio": 1, + "digit": "auto" + }, + "netLine": { + "show": false, + "width": 1, + "type": "solid", + "color": "auto", + "interval": { + "value": "auto", + "cusNumber": 0 + } + }, + "netArea": { + "show": false, + "interval": { + "value": "auto", + "cusNumber": 0 + }, + "colorOne": "auto", + "colorTwo": "auto" + }, + "data": [ + "BUS", + "UBER", + "TAXI", + "SUBWAY" + ], + "type": "category" + }, + "yAxisLeft": { + "show": true, + "title": { + "showTitle": false, + "text": "", + "nameGap": 15, + "rotate": 0, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "fzPosition": "end" + }, + "name": "显示Y轴", + "inverse": false, + "tickLine": { + "show": true, + "width": 1, + "color": "auto" + }, + "tick": { + "show": true, + "position": "outside", + "length": 5, + "width": 1, + "color": "auto" + }, + "tickLabel": { + "show": true, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "rotate": 0, + "formatter": { + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto" + }, + "split": 5, + "min": null, + "max": null, + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto", + "distance": 0 + }, + "netLine": { + "show": false, + "width": 1, + "type": "solid", + "color": "auto", + "interval": { + "value": "auto", + "cusNumber": 0 + } + }, + "netArea": { + "show": false, + "interval": { + "value": "auto", + "cusNumber": 0 + }, + "colorOne": "auto", + "colorTwo": "auto" + }, + "type": "value" + }, + "yAxisRight": { + "show": false, + "title": { + "showTitle": false, + "text": "", + "nameGap": 15, + "rotate": 0, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "fzPosition": "end" + }, + "name": "显示Y轴", + "inverse": false, + "tickLine": { + "show": true, + "width": 1, + "color": "auto" + }, + "tick": { + "show": true, + "position": "outside", + "length": 5, + "width": 1, + "color": "auto" + }, + "tickLabel": { + "show": true, + "label": { + "fontSize": 12, + "color": "#333", + "fontFamily": "sans-serif", + "fontGroup": [], + "cusFontSize": 12 + }, + "rotate": 0, + "formatter": { + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto" + }, + "split": 5, + "min": null, + "max": null, + "prefix": "", + "suffix": "", + "ratio": 1, + "digit": "auto", + "distance": 0 + }, + "netLine": { + "show": false, + "width": 1, + "type": "solid", + "color": "auto", + "interval": { + "value": "auto", + "cusNumber": 0 + } + }, + "netArea": { + "show": false, + "interval": { + "value": "auto", + "cusNumber": 0 + }, + "colorOne": "auto", + "colorTwo": "auto" + } + } + } + } + }, + "isShow": true + } + ``` + ::: + +------------ +### allowEdit +- 类型:Boolean +- 默认值:true +- 作用: 此sheet页是否允许编辑 + +------------ +### zoomRatio +- 类型:Number +- 默认值:1 +- 作用: 此sheet页的缩放比例,为0~1之间的二位小数数字。比如`0.1`、`0.56` + +------------ + +## 调试信息 + +初始化所需要的参数,会从简洁的角度出发来考虑设计,但是本地存储的参数则不同。 + +Luckysheet在初始化完成之后进行的一系列操作,会将更多本地参数存储在luckysheetfile中,作为本地使用的参数,实现一些类似Store数据中心的作用。比如,freezen的参数格式也会变化。 + +此时的luckysheetfile包含很多非初始化使用的本地参数,可用于调试代码、本地状态分析。如下展示了更丰富luckysheetfile信息,可通过方法 `luckysheet.getluckysheetfile()`获得: + +::: details +```json +[ + { + "name": "Cell", //工作表名称 + "color": "", //工作表颜色 + "index": 0, //工作表索引 + "status": 1, //激活状态 + "order": 0, //工作表的顺序 + "hide": 0,//是否隐藏 + "row": 36, //行数 + "column": 18, //列数 + "celldata": [], //初始化使用的单元格数据 + "config": { + "merge":{}, //合并单元格 + "rowlen":{}, //表格行高 + "columnlen":{}, //表格列宽 + "rowhidden":{}, //隐藏行 + "colhidden":{}, //隐藏列 + "borderInfo":{}, //边框 + }, + "scrollLeft": 0, //左右滚动条位置 + "scrollTop": 315, //上下滚动条位置 + "luckysheet_select_save": [], //选中的区域 + "calcChain": [],//公式链 + "isPivotTable":false,//是否数据透视表 + "pivotTable":{},//数据透视表设置 + "filter_select": {},//筛选范围 + "filter": null,//筛选配置 + "luckysheet_alternateformat_save": [], //交替颜色 + "luckysheet_alternateformat_save_modelCustom": [], //自定义交替颜色 + "luckysheet_conditionformat_save": {},//条件格式 + "frozen": {}, //冻结行列配置 + "freezen": {}, //冻结行列的渲染数据存储 + "chart": [], //图表配置 + "allowEdit": true, //是否允许编辑 + "zoomRatio":1, // 缩放比例 + + + "visibledatarow": [], //所有行的位置 + "visibledatacolumn": [], //所有列的位置 + "ch_width": 2322, //工作表区域的宽度 + "rh_height": 949, //工作表区域的高度 + "load": "1", //已加载过此sheet的标识 + "data": [], //更新和存储使用的单元格数据 + }, + { + "name": "Sheet2", + "color": "", + "index": 1, + "status": 0, + "order": 1, + "celldata": [], + "config": {} + }, + { + "name": "Sheet3", + "color": "", + "index": 2, + "status": 0, + "order": 2, + "celldata": [], + "config": {}, + } +] +``` +::: + +### visibledatarow +- 类型:Number +- 默认值:[] +- 作用: 所有行的位置信息,递增的行位置数据,初始化无需设置 + +------------ +### visibledatacolumn +- 类型:Number +- 默认值:[] +- 作用: 所有列的位置信息,递增的列位置数据,初始化无需设置 + +------------ +### ch_width +- 类型:Number +- 默认值:2322 +- 作用: 整个工作表区域的宽度(包含边界的灰色区域),初始化无需设置 + +------------ +### rh_height +- 类型:Number +- 默认值:2322 +- 作用: 整个工作表区域的高度(包含边界的灰色区域),初始化无需设置 + +------------ +### load +- 类型:Number +- 默认值:0 +- 作用: 当前sheet是否加载过,内部标识,初始化无需设置 + +------------ +### data +- 类型:Array +- 默认值:[] +- 作用: 初始化时从celldata转换而来,后续操作表格的数据更新,会更新到这个data字段中,初始化无需设置 +- 示例: + 以下是一个二行二列的数据 + ```json + [ + [{ + ct: {fa: "General", t: "g"}, + m:"value1", + v:"value1" + }, { + ct: {fa: "General", t: "g"}, + m:"value2", + v:"value2" + }], + [{ + ct: {fa: "General", t: "g"}, + m:"value3", + v:"value3" + }, { + ct: {fa: "General", t: "g"}, + m:"value4", + v:"value4" + }] + ] + + ``` + +------------ From 6da076dc56071020245d67547ce6dd13eb41dc8d Mon Sep 17 00:00:00 2001 From: liuyang Date: Wed, 9 Sep 2020 18:17:41 +0800 Subject: [PATCH 03/19] refactor(inline string develop): develop --- src/global/getRowlen.js | 142 ++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 36 deletions(-) diff --git a/src/global/getRowlen.js b/src/global/getRowlen.js index f0566e4..66197e1 100644 --- a/src/global/getRowlen.js +++ b/src/global/getRowlen.js @@ -416,7 +416,7 @@ function getCellTextInfo(cell , ctx, option){ textContent.rotate = rt; rt = Math.abs(rt); - let anchor = 0, preHeight = 0, preWidth=0, preStr, preTextHeight; + let anchor = 0, preHeight = 0, preWidth=0, preStr, preTextHeight, preTextWidth; for(let i = 1; i <= value.length; i++){ let str = value.substring(anchor, i); let measureText = getMeasureText(str, ctx); @@ -434,7 +434,7 @@ function getCellTextInfo(cell , ctx, option){ } if(rt!=0){//rotate - if(height>cellHeight){ + if((height+space_height)>cellHeight){ anchor = i-1; text_all_split[splitIndex].push({ @@ -445,7 +445,10 @@ function getCellTextInfo(cell , ctx, option){ left:0, top:0, splitIndex:splitIndex, - textHeight:preTextHeight + textHeight:preTextHeight, + textWidth:preTextWidth, + asc:measureText.actualBoundingBoxAscent, + desc:measureText.actualBoundingBoxDescent }); splitIndex +=1; @@ -460,12 +463,15 @@ function getCellTextInfo(cell , ctx, option){ left:0, top:0, splitIndex:splitIndex, - textHeight:textHeight + textHeight:textHeight, + textWidth:textWidth, + asc:measureText.actualBoundingBoxAscent, + desc:measureText.actualBoundingBoxDescent }); } } else{//plain - if(width>cellWidth){ + if((width+space_width)>cellWidth){ anchor = i-1; @@ -477,6 +483,8 @@ function getCellTextInfo(cell , ctx, option){ left:0, top:0, splitIndex:splitIndex, + asc:measureText.actualBoundingBoxAscent, + desc:measureText.actualBoundingBoxDescent }); splitIndex +=1; @@ -491,6 +499,8 @@ function getCellTextInfo(cell , ctx, option){ left:0, top:0, splitIndex:splitIndex, + asc:measureText.actualBoundingBoxAscent, + desc:measureText.actualBoundingBoxDescent }); } } @@ -499,15 +509,21 @@ function getCellTextInfo(cell , ctx, option){ preHeight = height; preStr = str; preTextHeight = textHeight; + preTextWidth = textWidth; } let split_all_size = []; - for(let i = 0; i <= splitIndex; i++){ + console.log(splitIndex, text_all_split); + let splitLen = Object.keys(text_all_split).length; + for(let i = 0; i < splitLen; i++){ let splitLists = text_all_split[i]; + if(splitLists==null){ + continue; + } let sWidth = 0, sHeight=0, textHeight=0; for(let s=0;s Date: Wed, 9 Sep 2020 19:40:41 +0800 Subject: [PATCH 04/19] update sheet and review data --- docs/guide/data.md | 10 +- docs/guide/sheet.md | 298 ++++++++++++++++++++++---------------------- 2 files changed, 154 insertions(+), 154 deletions(-) diff --git a/docs/guide/data.md b/docs/guide/data.md index 663cb89..a12e551 100644 --- a/docs/guide/data.md +++ b/docs/guide/data.md @@ -91,13 +91,13 @@ ## status - Type:Number - Default:1 - - Usage: Active state, there is only one active worksheet, other worksheets are 0 + - Usage:Active state, there is only one active worksheet which number will be 1 and the other worksheets are 0 ------------ ## order - Type:Number - Default:0 - - Usage: The index of the worksheets, it will increase when a worksheet is added, starting from 0 + - Usage: The index of the worksheets is starting from 0. it will increase when a worksheet is added. ------------ ## hide @@ -109,13 +109,13 @@ ## row - Type:Number - Default:36 - - Usage: Number of cell rows + - Usage: The number of cell rows ------------ ## column - Type:Number - Default:18 - - Usage: Number of cell columns + - Usage: The number of cell columns ------------ ## scrollLeft @@ -195,7 +195,7 @@ - Default:{} - Usage:Hidden row information, Rows:`rowhidden[Rows]: 0`, - `key` specify the number of rows,`value` is always `0` + you should specify the number of rows by `key`,`value` is always `0` - example: ```js "rowhidden": { diff --git a/docs/guide/sheet.md b/docs/guide/sheet.md index 1dda39b..a3f4520 100644 --- a/docs/guide/sheet.md +++ b/docs/guide/sheet.md @@ -64,57 +64,57 @@ eg: options.data: ``` ### name -- 类型:String -- 默认值:"Sheet1" -- 作用:工作表名称 +- type:String +- default:"Sheet1" +- usage:the name of a sheet ------------ ### color -- 类型:String -- 默认值:"##f20e0e" -- 作用:工作表颜色,工作表名称下方会有一条底部边框 +- type:String +- default:"##f20e0e" +- usage:Sheet color, with a bottom border below the sheet name ------------ ### index -- 类型:Number -- 默认值:0 -- 作用:工作表索引,从0开始 +- type:Number +- default:0 +- usage:Worksheet index, starting from 0 ------------ ### status -- 类型:Number -- 默认值:1 -- 作用: 激活状态,仅有一个激活状态的工作表,其他工作表为 0 +- type:Number +- default:1 +- usage:Active state, there is only one active worksheet which number will be 1 and the other worksheets are 0 ------------ ### order -- 类型:Number -- 默认值:0 -- 作用: 工作表的索引,新增工作表时会递增,从0开始 +- type:Number +- default:0 +- usage: The index of the worksheets is starting from 0. it will increase when a worksheet is added. ------------ ### hide -- 类型:Number -- 默认值:0 -- 作用: 是否隐藏,`0`为不隐藏,`1`为隐藏 +- type:Number +- default:0 +- usage: is the sheet is hidden. `0` means not to hide, `1` means hide ------------ ### row -- 类型:Number -- 默认值:36 -- 作用: 单元格行数 +- type:Number +- default:36 +- usage: Number of cell rows ------------ ### column -- 类型:Number -- 默认值:18 -- 作用: 单元格列数 +- type:Number +- default:18 +- usage: The number of cell columns ------------ ### celldata -- 类型:Array -- 默认值:[] -- 作用: 原始单元格数据集,存储sheet中所有单元格中的值,是一个包含`{r:0,c:0,v:{m:"value",v:"value",ct: {fa: "General", t: "g"}}}`格式单元格信息的一维数组,只在初始化的时候使用。 +- type:Array +- default:[] +- usage: 原始单元格数据集,存储sheet中所有单元格中的值,是一个包含`{r:0,c:0,v:{m:"value",v:"value",ct: {fa: "General", t: "g"}}}`格式单元格信息的一维数组,只在初始化的时候使用。 r代表行,c代表列,v代表该单元格的值,值可以是字符、数字或者对象。 @@ -122,7 +122,7 @@ eg: options.data: 使用celldata初始化完表格后,数据转换为luckysheetfile中的字段[data](#data),如`luckysheetfile[i].data`,后续操作表格的数据更新,会更新到这个data字段中,celldata不再使用。 -- 示例: +- example: ```js [{ "r": 0, @@ -146,17 +146,17 @@ eg: options.data: ------------ ### config -- 类型:Object -- 默认值:{} -- 作用:表格行高、列宽、合并单元格、边框、隐藏行等设置 - - 注意,config如果为空,必须为空对象`{}`,不能为字符串或者null +- type:Object +- default:{} +- usage:Table row height, column width, merged cells, borders, hidden rows and other settings + please be careful, config must be empty object `{}`, rather than empty string `""` or `null` + #### config.merge -- 类型:Object -- 默认值:{} -- 作用:合并单元格设置 -- 示例: +- type:Object +- default:{} +- usage:Merge cell settings +- example: ```js { "13_5": { @@ -179,13 +179,13 @@ eg: options.data: } } ``` - 对象中的`key`为`r + '_' + c`的拼接值,`value`为左上角单元格信息: r:行数,c:列数,rs:合并的行数,cs:合并的列数 + The `key` in the object is the spliced value of `r +'_' + c`, and the `value` is the cell information in the upper left corner: r: number of rows, c: number of columns, rs: number of merged rows, cs: merge Number of columns #### config.rowlen -- 类型:Object -- 默认值:{} -- 作用:每个单元格的行高 -- 示例: +- type:Object +- default:{} +- usage:The row height of each cell +- example: ```js "rowlen": { "0": 20, @@ -195,10 +195,10 @@ eg: options.data: ``` #### config.columnlen -- 类型:Object -- 默认值:{} -- 作用:每个单元格的列宽 -- 示例: +- type:Object +- default:{} +- usage:The column width of each cell +- example: ```js "columnlen": { "0": 97, @@ -208,12 +208,12 @@ eg: options.data: ``` #### config.rowhidden -- 类型:Object -- 默认值:{} -- 作用:隐藏行信息,格式为:`rowhidden[行数]: 0`, +- type:Object +- default:{} +- usage:Hidden row information, Rows:`rowhidden[Rows]: 0`, - `key`指定行数即可,`value`总是为`0` -- 示例: + you should specify the number of rows by `key`,`value` is always `0` +- example: ```js "rowhidden": { "30": 0, @@ -222,13 +222,13 @@ eg: options.data: ``` #### config.colhidden -- 类型:Object -- 默认值:{} -- 作用:隐藏列 +- type:Object +- default:{} +- usage:Hidden row information, Rows:`rowhidden[Rows]: 0`, 格式为:`colhidden[列数]: 0`, `key`指定列数即可,`value`总是为`0` -- 示例: +- example: ```js "colhidden": { "30": 0, @@ -237,10 +237,10 @@ eg: options.data: ``` #### config.borderInfo -- 类型:Object -- 默认值:{} -- 作用:单元格的边框信息 -- 示例: +- type:Object +- default:{} +- usage:单元格的边框信息 +- example: ```js "borderInfo": [{ "rangeType": "cell", @@ -285,21 +285,21 @@ eg: options.data: }] }] ``` - 范围类型分单个单元格和选区两种情况 - 1. 选区 `rangeType: "range"` + The range type can be divided into single cell and selected area + 1. selection `rangeType: "range"` - + 边框类型 `borderType:"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none"`, - + 边框粗细 `style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` - + 边框颜色 `color: 16进制颜色值` - + 选区范围 `range: 行列信息数组` + + Border type `borderType:"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none"`, + + Border thickness `style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` + + Border color `color: Hexadecimal color value` + + Selection area `range: Row and column information array` - 2. 单个单元格 `rangeType:"cell"` - + 单元格的行数和列数索引 `value.row_index: 数字,value.col_index: 数字` - + 四个边框对象 `value.l:左边框,value.r:右边框,value.t:上边框,value.b:下边框` - + 边框粗细 `value.l.style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` - + 边框颜色 `value.l.color: 16进制颜色值` + 2. Single cell `rangeType:"cell"` + + Number of rows and columns `value.row_index: number,value.col_index: number` + + Four border objects `value.l:Left border,value.r:Right border,value.t:Top border,value.b:Bottom border` + + Border thickness `value.l.style: 1 Thin | 2 Hair | 3 Dotted | 4 Dashed | 5 DashDot | 6 DashDotDot | 7 Double | 8 Medium | 9 MediumDashed | 10 MediumDashDot | 11 MediumDashDotDot | 12 SlantedDashDot | 13 Thick` + + Border color `value.l.color: Hexadecimal color value` - 更多模板: + templates: + ```js { @@ -313,7 +313,7 @@ eg: options.data: }] } ``` - 表示设置范围为`{"row": [7, 8],"column": [2, 3]}`的选区,类型为所有边框,边框粗细为`Dotted`,颜色为`"#0000ff"` + 表示设置范围为`{"row": [7, 8],"column": [2, 3]}`的选区,type为所有边框,边框粗细为`Dotted`,颜色为`"#0000ff"` + ```js { @@ -344,22 +344,22 @@ eg: options.data: ------------ ### scrollLeft -- 类型:Number -- 默认值:0 -- 作用: 左右滚动条位置 +- type:Number +- default:0 +- usage: Left and right scroll bar position ------------ ### scrollTop -- 类型:Number -- 默认值:0 -- 作用: 上下滚动条位置 +- type:Number +- default:0 +- usage: Up and down scroll bar position ------------ ### luckysheet_select_save -- 类型:Array -- 默认值:[] -- 作用: 选中的区域,支持多选,是一个包含多个选区对象的一维数组 -- 示例: +- type:Array +- default:[] +- usage: 选中的区域,支持多选,是一个包含多个选区对象的一维数组 +- example: ```js [ { @@ -379,10 +379,10 @@ eg: options.data: ------------ ### calcChain -- 类型:Array -- 默认值:[] -- 作用: 公式链,用于公式所链接的单元格改变后,所有引用此单元格的公式都会联动刷新 -- 示例: +- type:Array +- default:[] +- usage: 公式链,用于公式所链接的单元格改变后,所有引用此单元格的公式都会联动刷新 +- example: ```js [{ "r": 6, //行数 @@ -407,16 +407,16 @@ eg: options.data: ------------ ### isPivotTable -- 类型:Boolean -- 默认值:false -- 作用: 是否数据透视表 +- type:Boolean +- default:false +- usage: 是否数据透视表 ------------ ### pivotTable -- 类型:Object -- 默认值:{} -- 作用: 数据透视表设置 -- 示例: +- type:Object +- default:{} +- usage: 数据透视表设置 +- example: ```js { "pivot_select_save": { @@ -457,10 +457,10 @@ eg: options.data: ------------ ### filter_select -- 类型:Object -- 默认值:{} -- 作用: 筛选范围,一个选区,一个sheet只有一个筛选范围,类似`luckysheet_select_save` -- 示例: +- type:Object +- default:{} +- usage: 筛选范围,一个选区,一个sheet只有一个筛选范围,类似`luckysheet_select_save` +- example: ```js { @@ -471,14 +471,14 @@ eg: options.data: ------------ ### filter -- 类型:Object -- 默认值:{} -- 作用: 筛选的具体设置 -- 示例: +- type:Object +- default:{} +- usage: 筛选的具体设置 +- example: ```js { "0": { - "caljs": { // 条件筛选类型 + "caljs": { // 条件筛选type "value": "cellnull", "text": "Is empty", "type": "0" @@ -506,10 +506,10 @@ eg: options.data: ------------ ### luckysheet_alternateformat_save -- 类型:Array -- 默认值:[] -- 作用: 交替颜色配置 -- 示例: +- type:Array +- default:[] +- usage: 交替颜色配置 +- example: ```js [{ "cellrange": { //单元格范围 @@ -566,10 +566,10 @@ eg: options.data: ------------ ### luckysheet_alternateformat_save_modelCustom -- 类型:Array -- 默认值:[] -- 作用:自定义交替颜色,包含多个自定义交替颜色的配置 -- 示例: +- type:Array +- default:[] +- usage:自定义交替颜色,包含多个自定义交替颜色的配置 +- example: ```js [{ "head": { //页眉颜色 @@ -593,9 +593,9 @@ eg: options.data: ------------ ### luckysheet_conditionformat_save -- 类型:Array -- 默认值:[] -- 作用: 条件格式配置信息,包含多个条件格式配置对象的一维数组, +- type:Array +- default:[] +- usage: 条件格式配置信息,包含多个条件格式配置对象的一维数组, type: "default": 突出显示单元格规则和项目选区规则, @@ -606,7 +606,7 @@ eg: options.data: "colorGradation": 色阶 API中对此设置也有介绍[API setRangeConditionalFormat](/zh/guide/api.html) -- 示例: +- example: ```js [ { @@ -621,7 +621,7 @@ eg: options.data: "textColor": "#000000", "cellColor": "#ff0000" }, - "conditionName": "betweenness", //类型 + "conditionName": "betweenness", //type "conditionRange": [ //条件值所在单元格 { "row": [ 4, 4 ], @@ -681,9 +681,9 @@ eg: options.data: ------------ ### frozen -- 类型:Array -- 默认值:[] -- 作用: 冻结行列设置,分为6种类型 +- type:Array +- default:[] +- usage: 冻结行列设置,分为6种type 1. "row": 冻结首行 2. "column": 冻结首列 3. "both": 冻结行列 @@ -698,7 +698,7 @@ eg: options.data: 注意一点,luckysheetfile中还有一个配置freezen,其中的freezenhorizontaldata仍然用作本地数据,但是不发给后台存储,只做本地调试。 -- 示例: +- example: - 冻结首行 ```json { @@ -722,10 +722,10 @@ eg: options.data: ------------ ### chart -- 类型:Array -- 默认值:[] -- 作用: 图表配置,参照chartMix的配置格式,允许只设置想要的图表属性,一个完整的配置案例如下。 -- 示例: +- type:Array +- default:[] +- usage: 图表配置,参照chartMix的配置格式,允许只设置想要的图表属性,一个完整的配置案例如下。 +- example: :::::: details ```json { @@ -1195,15 +1195,15 @@ eg: options.data: ------------ ### allowEdit -- 类型:Boolean -- 默认值:true -- 作用: 此sheet页是否允许编辑 +- type:Boolean +- default:true +- usage: 此sheet页是否允许编辑 ------------ ### zoomRatio -- 类型:Number -- 默认值:1 -- 作用: 此sheet页的缩放比例,为0~1之间的二位小数数字。比如`0.1`、`0.56` +- type:Number +- default:1 +- usage: 此sheet页的缩放比例,为0~1之间的二位小数数字。比如`0.1`、`0.56` ------------ @@ -1211,7 +1211,7 @@ eg: options.data: 初始化所需要的参数,会从简洁的角度出发来考虑设计,但是本地存储的参数则不同。 -Luckysheet在初始化完成之后进行的一系列操作,会将更多本地参数存储在luckysheetfile中,作为本地使用的参数,实现一些类似Store数据中心的作用。比如,freezen的参数格式也会变化。 +Luckysheet在初始化完成之后进行的一系列操作,会将更多本地参数存储在luckysheetfile中,作为本地使用的参数,实现一些类似Store数据中心的usage。比如,freezen的参数格式也会变化。 此时的luckysheetfile包含很多非初始化使用的本地参数,可用于调试代码、本地状态分析。如下展示了更丰富luckysheetfile信息,可通过方法 `luckysheet.getluckysheetfile()`获得: @@ -1284,40 +1284,40 @@ Luckysheet在初始化完成之后进行的一系列操作,会将更多本地 ::: ### visibledatarow -- 类型:Number -- 默认值:[] -- 作用: 所有行的位置信息,递增的行位置数据,初始化无需设置 +- type:Number +- default:[] +- usage: 所有行的位置信息,递增的行位置数据,初始化无需设置 ------------ ### visibledatacolumn -- 类型:Number -- 默认值:[] -- 作用: 所有列的位置信息,递增的列位置数据,初始化无需设置 +- type:Number +- default:[] +- usage: 所有列的位置信息,递增的列位置数据,初始化无需设置 ------------ ### ch_width -- 类型:Number -- 默认值:2322 -- 作用: 整个工作表区域的宽度(包含边界的灰色区域),初始化无需设置 +- type:Number +- default:2322 +- usage: 整个工作表区域的宽度(包含边界的灰色区域),初始化无需设置 ------------ ### rh_height -- 类型:Number -- 默认值:2322 -- 作用: 整个工作表区域的高度(包含边界的灰色区域),初始化无需设置 +- type:Number +- default:2322 +- usage: 整个工作表区域的高度(包含边界的灰色区域),初始化无需设置 ------------ ### load -- 类型:Number -- 默认值:0 -- 作用: 当前sheet是否加载过,内部标识,初始化无需设置 +- type:Number +- default:0 +- usage: 当前sheet是否加载过,内部标识,初始化无需设置 ------------ ### data -- 类型:Array -- 默认值:[] -- 作用: 初始化时从celldata转换而来,后续操作表格的数据更新,会更新到这个data字段中,初始化无需设置 -- 示例: +- type:Array +- default:[] +- usage: 初始化时从celldata转换而来,后续操作表格的数据更新,会更新到这个data字段中,初始化无需设置 +- example: 以下是一个二行二列的数据 ```json [ From 72a44e3859af92578c0cb867ab05678201df7378 Mon Sep 17 00:00:00 2001 From: danny <692763892@qq.com> Date: Wed, 9 Sep 2020 20:24:38 +0800 Subject: [PATCH 05/19] update english md --- docs/guide/data.md | 2 +- docs/guide/sheet.md | 142 ++++++++++++++++++++++---------------------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/docs/guide/data.md b/docs/guide/data.md index a12e551..d7d8298 100644 --- a/docs/guide/data.md +++ b/docs/guide/data.md @@ -267,7 +267,7 @@ }] }] ``` - There are two types of range: single cell and selection + The range type can be divided into single cell and selected area 1. selection `rangeType: "range"` + Border type `borderType:"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none"`, diff --git a/docs/guide/sheet.md b/docs/guide/sheet.md index a3f4520..bb20983 100644 --- a/docs/guide/sheet.md +++ b/docs/guide/sheet.md @@ -39,7 +39,7 @@ eg: options.data: "luckysheet_conditionformat_save": {},//condition format "frozen": {}, //freeze row and column configuration "chart": [], //Chart configuration - "allowEdit": true, //is editble + "allowEdit": true, //is editable "zoomRatio":1, // zoom ratio }, { @@ -358,7 +358,7 @@ eg: options.data: ### luckysheet_select_save - type:Array - default:[] -- usage: 选中的区域,支持多选,是一个包含多个选区对象的一维数组 +- usage: The selected area supports multiple selections and is a one-dimensional array containing multiple selection objects. - example: ```js [ @@ -385,11 +385,11 @@ eg: options.data: - example: ```js [{ - "r": 6, //行数 - "c": 3, //列数 - "index": 1, //工作表id + "r": 6, //the number of rows + "c": 3, //the number of columns + "index": 1, //sheet id "func": [true, 23.75, "=AVERAGE(D3:D6)"], //公式信息,包含公式计算结果和公式字符串 - "color": "w", //"w":采用深度优先算法 "b":普通计算 + "color": "w", //"w":use Depth-First-Search "b":Normal search "parent": null, "chidren": {}, "times": 0 @@ -409,13 +409,13 @@ eg: options.data: ### isPivotTable - type:Boolean - default:false -- usage: 是否数据透视表 +- usage: is PivotTable ------------ ### pivotTable - type:Object - default:{} -- usage: 数据透视表设置 +- usage: Pivot table settings - example: ```js { @@ -459,7 +459,7 @@ eg: options.data: ### filter_select - type:Object - default:{} -- usage: 筛选范围,一个选区,一个sheet只有一个筛选范围,类似`luckysheet_select_save` +- usage: Filter range, a selection area, a sheet has only one filter range, similar to the `luckysheet_select_save` - example: ```js { @@ -473,18 +473,18 @@ eg: options.data: ### filter - type:Object - default:{} -- usage: 筛选的具体设置 +- usage: filter settings - example: ```js { "0": { - "caljs": { // 条件筛选type + "caljs": { // filter type "value": "cellnull", "text": "Is empty", "type": "0" }, - "rowhidden": { "3": 0, "4": 0 }, // 隐藏行 - "optionstate": true, //是否开启配置 + "rowhidden": { "3": 0, "4": 0 }, // the hidden rows + "optionstate": true, //is config active "str": 2, // 范围,起始行 "edr": 6, // 范围,结束行 "cindex": 1, // 当前范围列索引 @@ -508,7 +508,7 @@ eg: options.data: ### luckysheet_alternateformat_save - type:Array - default:[] -- usage: 交替颜色配置 +- usage: Alternating color configuration - example: ```js [{ @@ -568,7 +568,7 @@ eg: options.data: ### luckysheet_alternateformat_save_modelCustom - type:Array - default:[] -- usage:自定义交替颜色,包含多个自定义交替颜色的配置 +- usage:Custom alternate colors, including multiple custom alternate colors configuration - example: ```js [{ @@ -576,15 +576,15 @@ eg: options.data: "fc": "#6aa84f", "bc": "#ffffff" }, - "one": { //第一种颜色 + "one": { //The first color "fc": "#000", "bc": "#ffffff" }, - "two": { //第二种颜色 + "two": { //The second color "fc": "#000", "bc": "#e5fbee" }, - "foot": { //页脚颜色 + "foot": { //The footer color "fc": "#000", "bc": "#a5efcc" } @@ -595,17 +595,17 @@ eg: options.data: ### luckysheet_conditionformat_save - type:Array - default:[] -- usage: 条件格式配置信息,包含多个条件格式配置对象的一维数组, +- usage: Conditional format configuration information, a one-dimensional array containing multiple conditional format configuration objects, - type: "default": 突出显示单元格规则和项目选区规则, + type: "default": Highlight cell rules and project selection rules, - "dataBar":数据条, + "dataBar":Data bar, - "icons":图标集, + "icons":Icon set, - "colorGradation": 色阶 + "colorGradation": Color scale - API中对此设置也有介绍[API setRangeConditionalFormat](/zh/guide/api.html) + You can get more detail in this API page[API setRangeConditionalFormat](/zh/guide/api.html) - example: ```js [ @@ -683,14 +683,14 @@ eg: options.data: ### frozen - type:Array - default:[] -- usage: 冻结行列设置,分为6种type - 1. "row": 冻结首行 - 2. "column": 冻结首列 - 3. "both": 冻结行列 +- usage: the settings of freeze row and column which is divided into 6 types冻结行列设置,分为6种type + 1. "row": the first freeze row + 2. "column": the first freeze column + 3. "both": the freeze rows and columns 4. "rangeRow": 冻结行到选区 5. "rangeColumn": 冻结列到选区 6. "rangeBoth": 冻结行列到选区 - 7. "cancel": 取消冻结 + 7. "cancel": cancel freeze 当设置冻结到选区的时候,需要设置开启冻结的单元格位置,格式为`{ row_focus:0, column_focus:0 }`,意为当前激活的单元格的行数和列数。 @@ -724,7 +724,7 @@ eg: options.data: ### chart - type:Array - default:[] -- usage: 图表配置,参照chartMix的配置格式,允许只设置想要的图表属性,一个完整的配置案例如下。 +- usage: Chart configuration, plz refer to chartMix configuration. Allows you to set only the desired chart properties. - example: :::::: details ```json @@ -746,7 +746,7 @@ eg: options.data: "defaultOption": { "title": { "show": false, - "text": "默认标题", + "text": "default title", "label": { "fontSize": 12, "color": "#333", @@ -1197,17 +1197,17 @@ eg: options.data: ### allowEdit - type:Boolean - default:true -- usage: 此sheet页是否允许编辑 +- usage: is this sheet editable ------------ ### zoomRatio - type:Number - default:1 -- usage: 此sheet页的缩放比例,为0~1之间的二位小数数字。比如`0.1`、`0.56` +- usage: the zoom ratio of a sheet, which is a two decimal digit between 0~1, like `0.1`、`0.56`. ------------ -## 调试信息 +## debug information 初始化所需要的参数,会从简洁的角度出发来考虑设计,但是本地存储的参数则不同。 @@ -1219,39 +1219,39 @@ Luckysheet在初始化完成之后进行的一系列操作,会将更多本地 ```json [ { - "name": "Cell", //工作表名称 - "color": "", //工作表颜色 - "index": 0, //工作表索引 - "status": 1, //激活状态 - "order": 0, //工作表的顺序 - "hide": 0,//是否隐藏 - "row": 36, //行数 - "column": 18, //列数 - "celldata": [], //初始化使用的单元格数据 + "name": "Cell", //Worksheet name + "color": "", //Worksheet color + "index": 0, //Worksheet index + "status": 1, //Worksheet active status + "order": 0, //The order of the worksheet + "hide": 0,//Whether worksheet hide + "row": 36, //the number of rows in a sheet + "column": 18, //the number of columns in a sheet + "celldata": [], //Initial the cell data "config": { - "merge":{}, //合并单元格 - "rowlen":{}, //表格行高 - "columnlen":{}, //表格列宽 - "rowhidden":{}, //隐藏行 - "colhidden":{}, //隐藏列 - "borderInfo":{}, //边框 + "merge":{}, //merged cells + "rowlen":{}, //Table row height + "columnlen":{}, //Table column width + "rowhidden":{}, //hidden rows + "colhidden":{}, //hidden columns + "borderInfo":{}, //borders }, - "scrollLeft": 0, //左右滚动条位置 - "scrollTop": 315, //上下滚动条位置 - "luckysheet_select_save": [], //选中的区域 - "calcChain": [],//公式链 - "isPivotTable":false,//是否数据透视表 - "pivotTable":{},//数据透视表设置 - "filter_select": {},//筛选范围 - "filter": null,//筛选配置 - "luckysheet_alternateformat_save": [], //交替颜色 - "luckysheet_alternateformat_save_modelCustom": [], //自定义交替颜色 - "luckysheet_conditionformat_save": {},//条件格式 - "frozen": {}, //冻结行列配置 + "scrollLeft": 0, //Left and right scroll bar position + "scrollTop": 315, //Up and down scroll bar position + "luckysheet_select_save": [], //selected area + "calcChain": [],//Formula chain + "isPivotTable":false,//Whether is pivot table + "pivotTable":{},//Pivot table settings + "filter_select": {},//Filter range + "filter": null,//Filter configuration + "luckysheet_alternateformat_save": [], //Alternate colors + "luckysheet_alternateformat_save_modelCustom": [], //Customize alternate colors + "luckysheet_conditionformat_save": {},//condition format + "frozen": {}, //freeze row and column configuration "freezen": {}, //冻结行列的渲染数据存储 - "chart": [], //图表配置 - "allowEdit": true, //是否允许编辑 - "zoomRatio":1, // 缩放比例 + "chart": [], //Chart configuration + "allowEdit": true, //is editable + "zoomRatio":1, // zoom ratio "visibledatarow": [], //所有行的位置 @@ -1286,39 +1286,39 @@ Luckysheet在初始化完成之后进行的一系列操作,会将更多本地 ### visibledatarow - type:Number - default:[] -- usage: 所有行的位置信息,递增的行位置数据,初始化无需设置 +- usage: Position information of all rows, incremental row position data, No need to set up for initialization置 ------------ ### visibledatacolumn - type:Number - default:[] -- usage: 所有列的位置信息,递增的列位置数据,初始化无需设置 +- usage: Position information of all columns, incremental column position data, No need to set up for initialization ------------ ### ch_width - type:Number - default:2322 -- usage: 整个工作表区域的宽度(包含边界的灰色区域),初始化无需设置 +- usage: The width of the entire worksheet area (the gray area including the border), No need to set up for initialization ------------ ### rh_height - type:Number - default:2322 -- usage: 整个工作表区域的高度(包含边界的灰色区域),初始化无需设置 +- usage: The height of the entire worksheet area (the gray area containing the border), No need to set up for initialization ------------ ### load - type:Number - default:0 -- usage: 当前sheet是否加载过,内部标识,初始化无需设置 +- usage: Check whether the current sheet has been loaded, internal indicator, initialization does not need to be set ------------ ### data - type:Array - default:[] -- usage: 初始化时从celldata转换而来,后续操作表格的数据更新,会更新到这个data字段中,初始化无需设置 +- usage: conveted from celldata in initialization stage. `data` will have the update operation data.Initialization does not need to be set - example: - 以下是一个二行二列的数据 + Here is a two row, two column data ```json [ [{ From 37910abea38dc37fcb5cc5b905c7b028e3390c10 Mon Sep 17 00:00:00 2001 From: swen-xiong <956665504@qq.com> Date: Thu, 10 Sep 2020 15:43:40 +0800 Subject: [PATCH 06/19] feat(api): add some api functions --- docs/zh/guide/api.md | 34 +- src/global/api.js | 1271 +++++++++++++++++++++++++++++++++++++++++- src/global/editor.js | 11 +- 3 files changed, 1309 insertions(+), 7 deletions(-) diff --git a/docs/zh/guide/api.md b/docs/zh/guide/api.md index d1beae1..df06f14 100644 --- a/docs/zh/guide/api.md +++ b/docs/zh/guide/api.md @@ -10,6 +10,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 单元格操作 ### getCellValue(row, column [,setting])
+- [x] $\color{#FF3030}已实现$ - **参数**: @@ -38,6 +39,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setCellValue(row, column, value [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -62,6 +64,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### clearCell(row, column [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -83,6 +86,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteCell(move, row, column [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: - {String} [move]: 删除后,右侧还是下方的单元格移动 @@ -110,6 +114,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setCellFormat(row, column, attr, value [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -152,6 +157,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### find(content [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -174,6 +180,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### replace(content, replaceContent [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -200,6 +207,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 行和列操作 ### setHorizontalFrozen(isRange [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -232,6 +240,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setVerticalFrozen(isRange [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -260,6 +269,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setBothFrozen(isRange [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -288,6 +298,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### cancelFrozen([setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -308,6 +319,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### insertRow(row [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -331,6 +343,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### insertColumn( column [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -354,6 +367,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteRow(rowStart, rowEnd [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -379,6 +393,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteColumn(columnStart, columnEnd [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -404,6 +419,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### hideRow(rowStart, rowEnd [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -429,6 +445,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### hideColumn(columnStart, columnEnd [,setting])(TODO) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -454,6 +471,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### showRow(rowStart, rowEnd [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -477,6 +495,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### showColumn(columnStart, columnEnd [,setting])(TODO) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -502,6 +521,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 选区操作 ### getRange() +- [x] $\color{#FF3030}已实现$ - **说明**: @@ -524,6 +544,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeValue([setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -656,6 +677,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeJson(title [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -701,6 +723,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeArray(dimensional [,setting]) +- [ ] $\color{green} TODO$ - **参数**: @@ -796,6 +819,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeDiagonal(type [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -875,6 +899,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeBoolean([setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -942,6 +967,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeValue(data [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1006,6 +1032,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeFormat(attr, value [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1071,6 +1098,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeMerge(type [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1124,6 +1152,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### cancelRangeMerge( [setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1145,6 +1174,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeSort(type [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1173,6 +1203,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeSortMulti(title, sort [,setting]) +- [x] $\color{#FF3030}已实现$ - **参数**: @@ -1191,7 +1222,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 - **示例**: - 设置当前工作表当前选区为自定义排序,数据具有标题行,且按第一列升序第二列降序的规则进行排序 - `luckysheet.setRangeSortMulti(true,{sort:[{ i:0,sort:'asc' },{ i:1,sort:'des' }]})` + `luckysheet.setRangeSortMulti(true,[{ i:0,sort:'asc' },{ i:1,sort:'des' }])` ------------ @@ -1536,7 +1567,6 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 + `"newMatrix"`: 生产新矩阵 - {PlainObject} [setting]: 可选参数 + {Array | Object | String} [range]: 选区范围,支持选区的格式为`"A1:B2"`、`"sheetName!A1:B2"`或者`{row:[0,1],column:[0,1]}`,只能为单个选区;默认为当前选区 - + {Number} [order]: 工作表索引;默认值为当前工作表索引 + {Function} [success]: 操作结束的回调函数 - **说明**: diff --git a/src/global/api.js b/src/global/api.js index 96a497a..8363b0e 100644 --- a/src/global/api.js +++ b/src/global/api.js @@ -1,8 +1,8 @@ import Store from "../store"; -import { getObjType } from "../utils/util"; +import { getObjType, chatatABC } from "../utils/util"; import formula from './formula'; import { getSheetIndex, getluckysheet_select_save } from "../methods/get"; -import { isRealNull, valueIsError, isRealNum, isEditMode } from "./validate"; +import { isRealNull, valueIsError, isRealNum, isEditMode, hasPartMC } from "./validate"; import { genarate, update } from './format'; import server from "../controllers/server"; import luckysheetConfigsetting from "../controllers/luckysheetConfigsetting"; @@ -14,7 +14,12 @@ import locale from "../locale/locale"; import tooltip from "./tooltip"; import { luckysheet_searcharray } from "../controllers/sheetSearch"; import { luckysheetDeleteCell, luckysheetextendtable, luckysheetdeletetable } from "./extend"; -import { getdatabyselection } from "./getdata"; +import { getdatabyselection, getcellvalue } from "./getdata"; +import selection from "../controllers/selection"; +import json from "./json"; +import { orderbydata } from "./sort"; +import editor from "./editor"; +import { rowlenByRange } from "./getRowlen"; const IDCardReg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i; @@ -1166,3 +1171,1263 @@ function getRangeArray(dimensional, options = {}) { // TODO } } + +/** + * 复制指定工作表指定单元格区域的数据,返回json格式的数据 + * @param {Boolean} isFirstRowTitle 是否首行为标题 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + */ +export function getRangeJson(isFirstRowTitle, options = {}) { + let curRange = Store.luckysheet_select_save; + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let { + range = curRange, + order = curSheetOrder + } = {...options} + let file = Store.luckysheetfile[order]; + let config = file.config; + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + if (!range || range.length > 1) { + if(isEditMode()){ + alert(locale_drag.noMulti); + } else{ + tooltip.info(locale_drag.noMulti, ""); + } + return; + } + + //复制范围内包含部分合并单元格,提示 + if(config["merge"] != null) { + let has_PartMC = false; + let r1 = range[0].row[0], + r2 = range[0].row[1], + c1 = range[0].column[0], + c2 = range[0].column[1]; + has_PartMC = hasPartMC(config, r1, r2, c1, c2); + + if(has_PartMC){ + if(isEditMode()){ + alert(locale().drag.noPartMerge); + } else{ + tooltip.info(locale().drag.noPartMerge, ""); + } + return; + } + } + let getdata = getdatabyselection(range, order); + let arr = []; + if (getdata.length === 0) { + return; + } + if (isFirstRowTitle) { + if (getdata.length === 1) { + let obj = {}; + for (let i = 0; i < getdata[0].length; i++) { + obj[getcellvalue(0, i, getdata)] = ""; + } + arr.push(obj); + } else { + for (let r = 1; r < getdata.length; r++) { + let obj = {}; + for (let c = 0; c < getdata[0].length; c++) { + if(getcellvalue(0, c, getdata) == undefined){ + obj[""] = getcellvalue(r, c, getdata); + }else{ + obj[getcellvalue(0, c, getdata)] = getcellvalue(r, c, getdata); + } + } + arr.push(obj); + } + } + } else { + let st = range[0]["column"][0]; + for (let r = 0; r < getdata.length; r++) { + let obj = {}; + for (let c = 0; c < getdata[0].length; c++) { + obj[chatatABC(c + st)] = getcellvalue(r, c, getdata); + } + arr.push(obj); + } + } + selection.copybyformat(new Event(), JSON.stringify(arr)); +} + +/** + * + * @param {String} type 对角线还是对角线偏移 "normal"-对角线 "anti"-反对角线 +"offset"-对角线偏移 + * @param {Object} options 可选参数 + * @param {Number} options.column type为offset的时候设置,对角偏移的列数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + */ +export function getRangeDiagonal(type, options = {}) { + let typeValues = ['normal', 'anti', 'offset']; + if (typeValues.indexOf(type) < 0) { + return console.error('The type parameter must be included in [\'normal\', \'anti\', \'offset\']') + } + + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let curRange = Store.luckysheet_select_save; + let { + column = 1, + range = curRange, + order = curSheetOrder + } = {...options} + + let file = Store.luckysheetfile[order]; + let config = file.config; + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + if (!range || range.length > 1) { + if(isEditMode()){ + alert(locale().drag.noMulti); + } else{ + tooltip.info(locale().drag.noMulti, ""); + } + return; + } + + //复制范围内包含部分合并单元格,提示 + if(config["merge"] != null) { + let has_PartMC = false; + let r1 = range[0].row[0], + r2 = range[0].row[1], + c1 = range[0].column[0], + c2 = range[0].column[1]; + has_PartMC = hasPartMC(config, r1, r2, c1, c2); + + if(has_PartMC){ + if(isEditMode()){ + alert(locale().drag.noPartMerge); + } else{ + tooltip.info(locale().drag.noPartMerge, ""); + } + return; + } + } + let getdata = getdatabyselection(range, order); + let arr = []; + if (getdata.length === 0) { + return; + } + + let clen = getdata[0].length; + switch (type) { + case 'normal': + for (let r = 0; r < getdata.length; r++) { + if (r >= clen) { + break; + } + arr.push(getdata[r][r]); + } + break; + case 'anti': + for (let r = 0; r < getdata.length; r++) { + if (r >= clen) { + break; + } + arr.push(getdata[r][clen - r - 1]); + } + break; + case 'offset': + if(column.toString() == "NaN"){ + if(isEditMode()){ + alert(locale().drag.inputCorrect); + } else{ + tooltip.info(locale().drag.inputCorrect, ""); + } + return; + } + + if(column < 0){ + if(isEditMode()){ + alert(locale().drag.offsetColumnLessZero); + } else{ + tooltip.info(locale().drag.offsetColumnLessZero, ""); + } + return; + } + + for (let r = 0; r < getdata.length; r++) { + if (r + column >= clen) { + break; + } + arr.push(getdata[r][r + column]); + } + break; + } + selection.copybyformat(new Event(), JSON.stringify(arr)); +} + +/** + * 复制指定工作表指定单元格区域的数据,返回布尔值的数据 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + */ +export function getRangeBoolean(options = {}) { + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder + } = {...options} + + let file = Store.luckysheetfile[order]; + let config = file.config; + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + + if (!range || range.length > 1) { + if(isEditMode()){ + alert(locale().drag.noMulti); + } else{ + tooltip.info(locale().drag.noMulti, ""); + } + return; + } + + //复制范围内包含部分合并单元格,提示 + if(config["merge"] != null) { + let has_PartMC = false; + let r1 = range[0].row[0], + r2 = range[0].row[1], + c1 = range[0].column[0], + c2 = range[0].column[1]; + has_PartMC = hasPartMC(config, r1, r2, c1, c2); + + if(has_PartMC){ + if(isEditMode()){ + alert(locale().drag.noPartMerge); + } else{ + tooltip.info(locale().drag.noPartMerge, ""); + } + return; + } + } + let getdata = getdatabyselection(range, order); + let arr = []; + if (getdata.length === 0) { + return; + } + for (let r = 0; r < getdata.length; r++) { + let a = []; + for (let c = 0; c < getdata[0].length; c++) { + let bool = false; + + let v; + if(getObjType(getdata[r][c]) == "object"){ + v = getdata[r][c].v; + } else{ + v = getdata[r][c]; + } + + if (v == null || v == "") { + bool = false; + } else { + v = parseInt(v); + if (v == null || v > 0) { + bool = true; + } else { + bool = false; + } + } + a.push(bool); + } + arr.push(a); + } + + selection.copybyformat(event, JSON.stringify(arr)); +} + +/** + * 将一个单元格数组数据赋值到指定的区域,数据格式同getRangeValue方法取到的数据。 + * @param {Array[Array]} data 要赋值的单元格二维数组数据,每个单元格的值,可以为字符串或数字,或为符合Luckysheet格式的对象 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Function} options.success 操作结束的回调函数 + */ +export function setRangeValue(data, options = {}) { + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + if (data == null) { + return console.error('The data which will be set to range cannot be null.') + } + if (range instanceof Array) { + return console.error('setRangeValue only supports a single selection.') + } + if (typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + let rowCount = range.row[1] - range.row[0] + 1, + columnCount = range.column[1] - range.column[0] + 1; + if (data.length !== rowCount || data[0].length !== columnCount) { + return console.error('The data to be set does not match the selection.') + } + + for (let i = 0; i < rowCount; i++) { + for (let j = 0; j < columnCount; j++) { + let row = range.row[0] + i, + column = range.column[0] + j; + setCellValue(row, column, data[i][j], {order: order}) + } + } + if (success && typeof success === 'function') { + success(); + } +} + +/** + * 设置指定范围的单元格格式,一般用作处理格式,赋值操作推荐使用setRangeValue方法 + * @param {String} attr 要赋值的单元格二维数组数据,每个单元格的值,可以为字符串或数字,或为符合Luckysheet格式的对象 + * @param {Number | String | Object} value 具体的设置值 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 设置参数的目标选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + */ +export function setSingleRangeFormat(attr, value, options = {}) { + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder, + } = {...options} + if (attr == null) { + return console.error('Arguments attr cannot be null or undefined.') + } + if (range instanceof Array) { + return console.error('setRangeValue only supports a single selection.') + } + if (typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + let rowCount = range.row[1] - range.row[0] + 1, + columnCount = range.column[1] - range.column[0] + 1; + if (data.length !== rowCount || data[0].length !== columnCount) { + return console.error('The data to be set does not match the selection') + } + + for (let i = 0; i < rowCount; i++) { + for (let j = 0; j < columnCount; j++) { + let row = range.row[0] + i, + column = range.column[0] + j; + setCellFormat(row, column, attr, value, {order: order}) + } + } +} + +/** + * 设置指定范围的单元格格式,一般用作处理格式。支持多选区设置 + * @param {String} attr 要赋值的单元格二维数组数据,每个单元格的值,可以为字符串或数字,或为符合Luckysheet格式的对象 + * @param {Number | String | Object} value 具体的设置值 + * @param {Object} options 可选参数 + * @param {Array | Object | String} options.range 设置参数的目标选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Function} options.success 操作结束的回调函数 + */ +export function setRangeFormat(attr, value, options = {}) { + let curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + if (range instanceof Array) { + for (let i = 0; i < range.length; i++) { + setSingleRangeFormat(range[i]) + } + } + if (success && typeof success === 'function') { + success() + } +} + +/** + * 为指定索引的工作表,选定的范围开启或关闭筛选功能 + * @param {String} type 打开还是关闭筛选功能 open-打开筛选功能,返回当前筛选的范围对象;close-关闭筛选功能,返回关闭前筛选的范围对象 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围 + * @param {Number} options.order + * @param {Object} options.success + */ +function setRangeFilter(type, options = {}) { + let typeValues = ['open', 'close']; + if (typeValues.indexOf(type) < 0) { + return console.error('The type parameter must be included in [\'open\', \'close\']') + } + let curSheetOrder = getSheetIndex(Store.currentSheetIndex), + curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + if(range > 1){ + const locale_splitText = locale().splitText; + if(isEditMode()){ + alert(locale_splitText.tipNoMulti); + } else{ + tooltip.info(locale_splitText.tipNoMulti, ""); + } + return; + } + + if(Store.luckysheetfile[order].isPivotTable){ + return; + } + // TODO to be continue +} + +/** + * 为指定索引的工作表,选定的范围设定合并单元格 + * @param {String} type 合并类型 all-全部合并 horizontal-水平合并 vertical-垂直合并 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Object} options.success 操作结束的回调函数 + */ +export function setRangeMerge(type, options = {}) { + let typeValues = ['all', 'horizontal', 'vertical']; + if (typeValues.indexOf(type) < 0) { + return console.error('The type parameter must be included in [\'all\', \'horizontal\', \'vertical\']') + } + + let curSheetOrder = getSheetIndex(Store.currentSheetIndex), + curRange = Store.luckysheet_select_save; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + let file = luckysheetfile[order], + cfg = file.config, + data = file.data; + + if (!(range instanceof Array)) { + range = [range] + } + + let isHasMc = false; //选区是否含有 合并的单元格 + for (let i = 0; i < range.length; i++) { + let rangeItem = range[i]; + if (rangeItem && typeof rangeItem === 'string' && formula.iscelldata(rangeItem)) { + rangeItem = formula.getcellrange(rangeItem) + } + let r1 = rangeItem.row[0], + r2 = rangeItem.row[1], + c1 = rangeItem.column[0], + c2 = rangeItem.column[1]; + + for(let r = r1; r <= r2; r++){ + for(let c = c1; c <= c2; c++){ + let cell = data[r][c]; + if(getObjType(cell) == "object" && ("mc" in cell)){ + isHasMc = true; + break; + } + } + if (isHasMc) { + break; + } + } + if (isHasMc) { + break; + } + } + + if (isHasMc) { + cancelRangeMerge({ + range: range, + order: order + }) + } else { + for (let i = 0; i < range.length; i++) { + let rangeItem = range[i]; + if (rangeItem && typeof rangeItem === 'string' && formula.iscelldata(rangeItem)) { + rangeItem = formula.getcellrange(rangeItem) + } + let r1 = rangeItem.row[0], + r2 = rangeItem.row[1], + c1 = rangeItem.column[0], + c2 = rangeItem.column[1]; + + if (type === 'all') { + let fv = {}, + isfirst = false; + for(let r = r1; r <= r2; r++){ + for(let c = c1; c <= c2; c++){ + let cell = data[r][c]; + + if(cell != null && (!isRealNull(cell.v) || cell.f != null) && !isfirst){ + fv = $.extend(true, {}, cell); + isfirst = true; + } + + data[r][c] = { "mc": { "r": r1, "c": c1 } }; + } + } + + data[r1][c1] = fv; + data[r1][c1].mc = { "r": r1, "c": c1, "rs": r2 - r1 + 1, "cs": c2 - c1 + 1 }; + + cfg["merge"][r1 + "_" + c1] = { "r": r1, "c": c1, "rs": r2 - r1 + 1, "cs": c2 - c1 + 1 }; + } else if (type === 'vertical') { + for(let c = c1; c <= c2; c++){ + let fv = {}, + isfirst = false; + + for(let r = r1; r <= r2; r++){ + let cell = data[r][c]; + + if(cell != null && (!isRealNull(cell.v) || cell.f != null) && !isfirst){ + fv = $.extend(true, {}, cell); + isfirst = true; + } + + data[r][c] = { "mc": { "r": r1, "c": c } }; + } + + data[r1][c] = fv; + data[r1][c].mc = { "r": r1, "c": c, "rs": r2 - r1 + 1, "cs": 1 }; + + cfg["merge"][r1 + "_" + c] = { "r": r1, "c": c, "rs": r2 - r1 + 1, "cs": 1 }; + } + } else if (type === 'horizontal') { + for(let r = r1; r <= r2; r++){ + let fv = {}, + isfirst = false; + + for(let c = c1; c <= c2; c++){ + let cell = data[r][c]; + + if(cell != null && (!isRealNull(cell.v) || cell.f != null) && !isfirst){ + fv = $.extend(true, {}, cell); + isfirst = true; + } + + data[r][c] = { "mc": { "r": r, "c": c1 } }; + } + + data[r][c1] = fv; + data[r][c1].mc = { "r": r, "c": c1, "rs": 1, "cs": c2 - c1 + 1 }; + + cfg["merge"][r + "_" + c1] = { "r": r, "c": c1, "rs": 1, "cs": c2 - c1 + 1 }; + } + } + } + } + + if (success && typeof success === 'function') { + success(); + } +} + +/** + * 为指定索引的工作表,选定的范围取消合并单元格 + * @param {Object} options 可选参数 + * @param {Array | Object | String} options.range 选区范围 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Object} options.success 操作结束的回调函数 + */ +export function cancelRangeMerge(options = {}) { + let curRange = Store.luckysheet_select_save[0], + curSheetOrder = getSheetIndex(Store.currentSheetIndex); + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + let file = luckysheetfile[order], + cfg = file.config, + data = file.data; + + if (!(range instanceof Array)) { + range = [range] + } + + for (let i = 0; i < range.length; i++) { + let rangeItem = range[i]; + if (rangeItem && typeof rangeItem === 'string' && formula.iscelldata(rangeItem)) { + rangeItem = formula.getcellrange(rangeItem) + } + let r1 = rangeItem.row[0], + r2 = rangeItem.row[1], + c1 = rangeItem.column[0], + c2 = rangeItem.column[1]; + if (r1 == r2 && c1 == c2) { + continue; + } + + let fv = {} + for(let r = r1; r <= r2; r++){ + for(let c = c1; c <= c2; c++){ + let cell = data[r][c]; + + if(cell != null && cell.mc != null){ + let mc_r = cell.mc.r, mc_c = cell.mc.c; + + if("rs" in cell.mc){ + delete cell.mc; + delete cfg["merge"][mc_r + "_" + mc_c]; + + fv[mc_r + "_" + mc_c] = $.extend(true, {}, cell); + } + else{ + let cell_clone = fv[mc_r + "_" + mc_c]; + delete cell_clone.v; + delete cell_clone.m; + delete cell_clone.ct; + delete cell_clone.f; + delete cell_clone.spl; + data[r][c] = cell_clone; + } + } + } + } + } + + // 当前sheet页合并时刷新 + if (order === curSheetOrder) { + jfrefreshgrid(data, range, cfg) + } +} + +/** + * 为指定索引的工作表,选定的范围开启排序功能,返回选定范围排序后的数据。 + * @param {String} type 排序类型 asc-升序 desc-降序 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Function} options.success 操作结束的回调函数 + */ +export function setRangeSort(type, options = {}) { + let typeValues = ['asc', 'desc'] + if (typeValues.indexOf(type) < 0) { + return console.error('The type parameter must be included in [\'asc\', \'desc\'') + } + + let curSheetOrder = getSheetIndex(Store.currentSheetIndex), + curRange = Store.luckysheet_select_save[0]; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + let file = Store.luckysheetfile[order], + cfg = file.config, + fileData = file.data; + + if(range instanceof Array && range.length > 1){ + if(isEditMode()){ + alert(locale().sort.noRangeError); + } else{ + tooltip.info(locale().sort.noRangeError, ""); + } + return; + } + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + let r1 = range.row[0], + r2 = range.row[1], + c1 = range.column[0], + c2 = range.column[1]; + + let hasMc = false; //Whether the sort selection has merged cells + let data = []; + for(let r = r1; r <= r2; r++){ + let data_row = []; + for(let c = c1; c <= c2; c++){ + if(fileData[r][c] != null && fileData[r][c].mc != null){ + hasMc = true; + break; + } + data_row.push(fileData[r][c]); + } + data.push(data_row); + } + if(hasMc){ + if(isEditMode()){ + alert(locale().sort.mergeError); + } else{ + tooltip.info(locale().sort.mergeError, ""); + } + return; + } + data = orderbydata([].concat(data), 0, type === 'asc'); + + for(let r = r1; r <= r2; r++){ + for(let c = c1; c <= c2; c++){ + fileData[r][c] = data[r - r1][c - c1]; + } + } + if(cfg["rowlen"] != null){ + let config = $.extend(true, {}, cfg); + config = rowlenByRange(fileData, r1, r2, config); + + if (order == Store.currentSheetIndex) { + jfrefreshgrid(fileData, [{ "row": [r1, r2], "column": [c1, c2] }], config, null, true); + } + } else{ + if (order == Store.currentSheetIndex) { + jfrefreshgrid(fileData, [{ "row": [r1, r2], "column": [c1, c2] }]); + } + } + + if (success && typeof success === 'function') { + success(); + } +} + +/** + * 为指定索引的工作表,选定的范围开启多列自定义排序功能,返回选定范围排序后的数据。 + * @param {Boolean} hasTitle 数据是否具有标题行 + * @param {Array} sort 列设置,设置需要排序的列索引和排序方式,格式如:[{ i:0,sort:'asc' },{ i:1,sort:'des' }] + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Number} options.order 工作表索引;默认值为当前工作表索引 + * @param {Function} options.success 操作结束的回调函数 + */ +export function setRangeSortMulti(hasTitle, sort, options = {}) { + if (!sort || !(sort instanceof Array)) { + return console.error('The sort parameter is invalid.') + } + + let curSheetOrder = getSheetIndex(Store.currentSheetIndex), + curRange = Store.luckysheet_select_save[0]; + let { + range = curRange, + order = curSheetOrder, + success + } = {...options} + let file = Store.luckysheetfile[order], + cfg = file.config, + fileData = file.data; + + if(range instanceof Array && range.length > 1){ + if(isEditMode()){ + alert(locale().sort.noRangeError); + } else{ + tooltip.info(locale().sort.noRangeError, ""); + } + return; + } + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + let r1 = range.row[0], + r2 = range.row[1], + c1 = range.column[0], + c2 = range.column[1]; + + let str; + if(hasTitle){ + str = r1 + 1; + } else{ + str = r1; + } + let hasMc = false; //Whether the sort selection has merged cells + let data = []; + for(let r = str; r <= r2; r++){ + let data_row = []; + for(let c = c1; c <= c2; c++){ + if(fileData[r][c] != null && fileData[r][c].mc != null){ + hasMc = true; + break; + } + data_row.push(fileData[r][c]); + } + data.push(data_row); + } + if(hasMc){ + if(isEditMode()){ + alert(locale().sort.mergeError); + } else{ + tooltip.info(locale().sort.mergeError, ""); + } + return; + } + sort.forEach(sortItem => { + let i = sortItem.i; + i -= c1; + data = orderbydata([].concat(data), i, sortItem.sort === 'asc'); + }) + + for(let r = str; r <= r2; r++){ + for(let c = c1; c <= c2; c++){ + fileData[r][c] = data[r - str][c - c1]; + } + } + if(cfg["rowlen"] != null){ + let config = $.extend(true, {}, cfg); + config = rowlenByRange(fileData, str, r2, config); + + if (order === Store.currentSheetIndex) { + jfrefreshgrid(fileData, [{ "row": [str, r2], "column": [c1, c2] }], config, null, true); + } + } else{ + if (order === Store.currentSheetIndex) { + jfrefreshgrid(fileData, [{ "row": [str, r2], "column": [c1, c2] }]); + } + } + + if (success && typeof success === 'function') { + success(); + } +} + +/** + * + * @param {String} move 删除后,右侧还是下方的单元格移动 + * @param {Object} options 可选参数 + */ +function deleteRange(move, options = {}) { + +} + +/** + * 指定工作表指定单元格区域的数据进行矩阵操作,返回操作成功后的结果数据 + * @param {String} type 矩阵操作的类型 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Function} options.success 操作结束的回调函数 + */ +export function matrixOperation(type, options = {}) { + let typeValues = [ + 'flipUpDown', // 上下翻转 + 'flipLeftRight', // 左右翻转 + 'flipClockwise', // 顺时针旋转 + 'flipCounterClockwise', // 逆时针旋转 + 'transpose', // 转置 + 'deleteZeroByRow', // 按行删除两端0值 + 'deleteZeroByColumn', // 按列删除两端0值 + 'removeDuplicateByRow', // 按行删除重复值 + 'removeDuplicateByColumn', // 按列删除重复值 + 'newMatrix' // 生产新矩阵 + ] + if (!type || typeValues.indexOf(type) < 0) { + return console.error('The type parameter is invalid.') + } + + let curRange = Store.luckysheet_select_save[0]; + let { + range = curRange, + success + } = {...options} + + if(range instanceof Array && range.length > 1){ + if(isEditMode()){ + alert(locale().drag.noMulti); + } else{ + tooltip.info(locale().drag.noMulti, ""); + } + return; + } + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + + let getdata = getdatabyselection(range); + let arr = []; + if (getdata.length === 0) { + return; + } + + let getdatalen, collen, arr1; + switch (type) { + case 'flipUpDown': + for (let r = getdata.length - 1; r >= 0; r--) { + let a = []; + for (let c = 0; c < getdata[0].length; c++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + } + a.push(value); + } + arr.push(a); + } + break; + case 'flipLeftRight': + for (let r = 0; r < getdata.length; r++) { + let a = []; + for (let c = getdata[0].length - 1; c >= 0; c--) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + } + a.push(value); + } + arr.push(a); + } + break; + case 'flipClockwise': + for (let c = 0; c < getdata[0].length; c++) { + let a = []; + for (let r = getdata.length - 1; r >= 0; r--) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + } + a.push(value); + } + arr.push(a); + } + break; + case 'flipCounterClockwise': + for (let c = getdata[0].length - 1; c >= 0; c--) { + let a = []; + for (let r = 0; r < getdata.length; r++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + } + a.push(value); + } + arr.push(a); + } + break; + case 'transpose': + for (let c = 0; c < getdata[0].length; c++) { + let a = []; + for (let r = 0; r < getdata.length; r++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + } + a.push(value); + } + arr.push(a); + } + break; + case 'deleteZeroByRow': + getdatalen = getdata[0].length; + for (let r = 0; r < getdata.length; r++) { + let a = [], stdel = true, eddel = true; + for (let c = 0; c < getdatalen; c++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + if ((value.v == "0" || value.v == 0) && stdel) { + continue; + } + else { + stdel = false; + } + } + a.push(value); + } + + let a1 = []; + if (a.length == getdatalen) { + a1 = a; + } else { + for (let c = a.length - 1; c >= 0; c--) { + let value = ""; + if (a[c] != null) { + value = a[c]; + if ((value.v == "0" || value.v == 0) && eddel) { + continue; + } + else { + eddel = false; + } + } + a1.unshift(value); + } + + let l = getdatalen - a1.length; + for (let c1 = 0; c1 < l; c1++) { + a1.push(""); + } + } + arr.push(a1); + } + break; + case 'deleteZeroByColumn': + getdatalen = getdata.length; + collen = getdata[0].length; + for (let c = 0; c < collen; c++) { + let a = [], stdel = true, eddel = true; + for (let r = 0; r < getdatalen; r++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + if ((value.v == "0" || value.v == 0) && stdel) { + continue; + } + else { + stdel = false; + } + } + a.push(value); + } + + let a1 = []; + if (a.length == getdatalen) { + a1 = a; + } + else { + for (let r = a.length - 1; r >= 0; r--) { + let value = ""; + if (a[r] != null) { + value = a[r]; + if ((value.v == "0" || value.v == 0) && eddel) { + continue; + } + else { + eddel = false; + } + } + a1.unshift(value); + } + + let l = getdatalen - a1.length; + for (let r1 = 0; r1 < l; r1++) { + a1.push(""); + } + } + arr.push(a1); + } + + arr1 = []; + for (let c = 0; c < arr[0].length; c++) { + let a = []; + for (let r = 0; r < arr.length; r++) { + let value = ""; + if (arr[r] != null && arr[r][c] != null) { + value = arr[r][c]; + } + a.push(value); + } + arr1.push(a); + } + break; + case 'removeDuplicateByRow': + getdatalen = getdata[0].length; + for (let r = 0; r < getdata.length; r++) { + let a = [], repeat = {}; + + for (let c = 0; c < getdatalen; c++) { + let value = null; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + + if(value.v in repeat){ + repeat[value.v].push(value); + } + else{ + repeat[value.v] = []; + repeat[value.v].push(value); + } + } + } + + for (let c = 0; c < getdatalen; c++) { + let value = null; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + + if(repeat[value.v].length == 1){ + a.push(value); + } + } + } + + let l = getdatalen - a.length; + for (let c1 = 0; c1 < l; c1++) { + a.push(null); + } + arr.push(a); + } + break; + case 'removeDuplicateByColumn': + collen = getdata[0].length; + getdatalen = getdata.length; + for (let c = 0; c < collen; c++) { + let a = [], repeat = {}; + + for (let r = 0; r < getdatalen; r++) { + let value = null; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + + if(value.v in repeat){ + repeat[value.v].push(value); + } + else{ + repeat[value.v] = []; + repeat[value.v].push(value); + } + } + } + + for (let r = 0; r < getdatalen; r++) { + let value = null; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + + if(repeat[value.v].length == 1){ + a.push(value); + } + } + } + + a1 = a; + let l = getdatalen - a1.length; + for (let r1 = 0; r1 < l; r1++) { + a1.push(null); + } + arr.push(a1); + } + + arr1 = []; + for (let c = 0; c < arr[0].length; c++) { + let a = []; + for (let r = 0; r < arr.length; r++) { + let value = null; + if (arr[r] != null && arr[r][c] != null) { + value = arr[r][c]; + } + a.push(value); + } + arr1.push(a); + } + break; + case 'newMatrix': + // TODO + console.log("TODO") + break; + } + editor.controlHandler(arr, range) + + if (success && typeof success === 'function') { + success(); + } +} + +/** + * 指定工作表指定单元格区域的数据进行矩阵计算,返回计算成功后的结果数据 + * @param {String} type 计算方式 + * @param {Number} number 计算数值 + * @param {Object} options 可选参数 + * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]},只能为单个选区;默认为当前选区 + * @param {Function} options.success 操作结束的回调函数 + */ +export function matrixCalculation(type, number, options = {}) { + let typeValues = [ + 'plus', // 加 + 'minus', // 减 + 'multiply', // 乘 + 'divided', // 除 + 'power', // 幂 + 'root', // 次方根 + 'log' // 对数log + ] + if (!type || typeValues.indexOf(type) < 0) { + return console.error('The type parameter is invalid.') + } + if(number.toString() == "NaN"){ + return console.error('The number parameter is invalid.') + } + + let curRange = Store.luckysheet_select_save[0]; + let { + range = curRange, + success + } = {...options} + + if(range instanceof Array && range.length > 1){ + if(isEditMode()){ + alert(locale().drag.noMulti); + } else{ + tooltip.info(locale().drag.noMulti, ""); + } + return; + } + + if (range && typeof range === 'string' && formula.iscelldata(range)) { + range = formula.getcellrange(range) + } + + let getdata = getdatabyselection(range); + if (getdata.length == 0) { + return; + } + let arr = []; + for (let r = 0; r < getdata.length; r++) { + let a = []; + for (let c = 0; c < getdata[0].length; c++) { + let value = ""; + if (getdata[r] != null && getdata[r][c] != null) { + value = getdata[r][c]; + if (parseInt(value) != null && getdata[r][c].ct != undefined && getdata[r][c].ct.t == "n") { + if (type == "minus") { + value.v = value.v - number; + } + else if (type == "multiply") { + value.v = value.v * number; + } + else if (type == "divided") { + value.v = numFormat(value.v / number, 4); + } + else if (type == "power") { + value.v = Math.pow(value.v, number); + } + else if (type == "root") { + if (number == 2) { + value.v = numFormat(Math.sqrt(value.v), 4); + } + else if (number == 3 && Math.cbrt) { + value.v = numFormat(Math.cbrt(value.v), 4); + } + else { + value.v = numFormat(jfnqrt(value.v, number), 4); + } + } + else if (type == "log") { + value.v = numFormat(Math.log(value.v) * 10000 / Math.log(Math.abs(number)), 4); + } + else { + value.v = value.v + number; + } + + if(value.v == null){ + value.m = ""; + } + else{ + value.m = value.v.toString(); + } + } + } + a.push(value); + } + arr.push(a); + } + + editor.controlHandler(arr, range); + + if (success && typeof success === 'function') { + success(); + } +} diff --git a/src/global/editor.js b/src/global/editor.js index 54ada9b..99ea8a2 100644 --- a/src/global/editor.js +++ b/src/global/editor.js @@ -60,12 +60,19 @@ const editor = { _this.deepCopyFlowDataCache = $.extend(true, [], flowData); } }, - controlHandler: function (dataChe) { + + /** + * @param {Array} dataChe + * @param {Object} range 是否指定选区,默认为当前选区 + * @since Add range parameter. Update by siwei@2020-09-10. + */ + controlHandler: function (dataChe, range) { let _this = this; let d = _this.deepCopyFlowData(Store.flowdata);//取数据 - let last = Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]; + // let last = Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]; + let last = range || Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]; let curR = last["row"] == null ? 0 : last["row"][0]; let curC = last["column"] == null ? 0 : last["column"][0]; let rlen = dataChe.length, clen = dataChe[0].length; From 66aecbe7fe16be03c9c62e1ebbf941c1a9f4bac7 Mon Sep 17 00:00:00 2001 From: lrz <1414556676@qq.com> Date: Fri, 11 Sep 2020 21:16:16 +0800 Subject: [PATCH 07/19] feat(api): api setCellValue --- README-zh.md | 3 +- README.md | 3 +- docs/zh/guide/api.md | 193 +++++++++++++++++++---- docs/zh/guide/sheet.md | 42 ++++- src/core.js | 3 +- src/function/functionlist.js | 1 - src/global/api.js | 294 +++++++++++++++++++---------------- src/global/formula.js | 82 +++++++++- 8 files changed, 441 insertions(+), 180 deletions(-) diff --git a/README-zh.md b/README-zh.md index ebe5d23..e3de471 100644 --- a/README-zh.md +++ b/README-zh.md @@ -10,10 +10,11 @@ 🚀Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源。 ## 文档 -[在线demo](https://mengshukeji.github.io/LuckysheetDemo/) [在线文档](https://mengshukeji.github.io/LuckysheetDocs/zh/) +[在线demo](https://mengshukeji.github.io/LuckysheetDemo/) / [导入excel demo](https://mengshukeji.github.io/LuckyexcelDemo/) + ![演示](/docs/.vuepress/public/img/LuckysheetDemo.gif) ## 插件 diff --git a/README.md b/README.md index c3003d8..bdfcb80 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,11 @@ English| [简体中文](./README-zh.md) 🚀Luckysheet is an online spreadsheet like excel that is powerful, simple to configure, and completely open source. ## Documentation -[Online demo](https://mengshukeji.github.io/LuckysheetDemo/) [Online documentation](https://mengshukeji.github.io/LuckysheetDocs/) +[Online demo](https://mengshukeji.github.io/LuckysheetDemo/) / [Import excel demo](https://mengshukeji.github.io/LuckyexcelDemo/) + ![Demo](/docs/.vuepress/public/img/LuckysheetDemo.gif) ## Plugins diff --git a/docs/zh/guide/api.md b/docs/zh/guide/api.md index df06f14..a4d9b00 100644 --- a/docs/zh/guide/api.md +++ b/docs/zh/guide/api.md @@ -10,7 +10,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 单元格操作 ### getCellValue(row, column [,setting])
-- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -39,7 +39,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setCellValue(row, column, value [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -48,6 +48,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 - {Object | String | Number} [value]: 要设置的值;可以为字符串或数字,或为符合Luckysheet单元格格式的对象,参考 [单元格属性表](/zh/guide/cell.html) - {PlainObject} [setting]: 可选参数 + {Number} [order]: 工作表索引;默认值为当前工作表索引 + + {Boolean} [isRefresh]: 是否刷新界面;默认为`true`;用于多个单元格赋值时候控制节流,前面单元格赋值的时候应设置为 `false`,最后一个单元格赋值时设置为`true`。 + {Function} [success]: 操作结束的回调函数 - **说明**: @@ -58,13 +59,23 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 - **示例**: - - 设置当前工作表"A1"单元格的值为"abc" -     `luckysheet.setCellValue(0, 0, 'abc');` + - 设置当前工作表"A1"单元格的值为"1" +     `luckysheet.setCellValue(0, 0, 1);` + + - 设置当前工作表"B1"单元格的值为公式"=sum(A1)" +     `luckysheet.setCellValue(0, 1, "=sum(A1)");` + + - 设置当前工作表"C1"单元格的值为公式"=sum(A1:B1",并带有红色背景,单元格对象可以不带v和m值,Luckysheet会根据公式信息自动计算结果,如果带了未更新或者是非公式结果的v和m值,Luckysheet也仍然会根据公式实际关联的数据计算出准备的结果。 +     `luckysheet.setCellValue(0, 2, {f: "=sum(A1:B1)", bg:"#FF0000"})` + + 再次设置"C1"单元格新的公式仍然可以生效 + + `luckysheet.setCellValue(0, 2, {f: "=sum(A1)", bg:"#00FF00"})` ------------ ### clearCell(row, column [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -86,7 +97,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteCell(move, row, column [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: - {String} [move]: 删除后,右侧还是下方的单元格移动 @@ -114,7 +125,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setCellFormat(row, column, attr, value [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -157,7 +168,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### find(content [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -180,7 +191,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### replace(content, replaceContent [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -207,7 +218,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 行和列操作 ### setHorizontalFrozen(isRange [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -240,7 +251,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setVerticalFrozen(isRange [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -269,7 +280,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setBothFrozen(isRange [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -298,7 +309,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### cancelFrozen([setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -319,7 +330,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### insertRow(row [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -343,7 +354,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### insertColumn( column [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -367,7 +378,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteRow(rowStart, rowEnd [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -393,7 +404,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### deleteColumn(columnStart, columnEnd [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -419,7 +430,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### hideRow(rowStart, rowEnd [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -445,7 +456,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### hideColumn(columnStart, columnEnd [,setting])(TODO) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -471,7 +482,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### showRow(rowStart, rowEnd [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -495,7 +506,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### showColumn(columnStart, columnEnd [,setting])(TODO) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -521,7 +532,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ## 选区操作 ### getRange() -- [x] $\color{#FF3030}已实现$ + - **说明**: @@ -544,7 +555,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeValue([setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -630,6 +641,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getRangeHtml([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -677,7 +691,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeJson(title [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -723,7 +737,10 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeArray(dimensional [,setting]) -- [ ] $\color{green} TODO$ + +[todo] + + - **参数**: @@ -819,7 +836,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeDiagonal(type [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -899,7 +916,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### getRangeBoolean([setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -929,6 +946,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setRangeShow(range [,setting])
+[todo] + + - **参数**: - {Array | Object | String} [range]: 选区范围,支持选区的格式为`"A1:B2"`、`"sheetName!A1:B2"`或者`{row:[0,1],column:[0,1]}`,允许多个选区组成的数组;默认为当前选区 @@ -967,7 +987,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeValue(data [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -975,6 +995,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 - {PlainObject} [setting]: 可选参数 + {Array | Object | String} [range]: 选区范围,支持选区的格式为`"A1:B2"`、`"sheetName!A1:B2"`或者`{row:[0,1],column:[0,1]}`,只能为单个选区;默认为当前选区 + {Number} [order]: 工作表索引;默认值为当前工作表索引 + + {Boolean} [isRefresh]: 是否刷新界面;默认为`true`;用于多个单元格赋值时候控制节流,前面单元格赋值的时候应设置为 `false`,最后一个单元格赋值时设置为`true`。 + {Function} [success]: 操作结束的回调函数 - **说明**: @@ -1032,7 +1053,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeFormat(attr, value [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -1074,6 +1095,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setRangeFilter(type [,setting]) +[todo] + + - **参数**: - {String} [type]: 打开还是关闭筛选功能 @@ -1098,7 +1122,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeMerge(type [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -1152,7 +1176,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### cancelRangeMerge( [setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -1174,7 +1198,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeSort(type [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -1203,7 +1227,7 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ------------ ### setRangeSortMulti(title, sort [,setting]) -- [x] $\color{#FF3030}已实现$ + - **参数**: @@ -1228,6 +1252,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setRangeConditionalFormatDefault(conditionName, conditionValue [,setting]) +[todo] + + - **参数**: - {String} [conditionName]: 条件格式规则类型 @@ -1330,6 +1357,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setRangeConditionalFormat(type [,setting]) +[todo] + + - **参数**: - {String} [type]: 条件格式规则类型 @@ -1448,6 +1478,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### deleteRangeConditionalFormat(itemIndex [,setting]) +[todo] + + - **参数**: - {Number} [itemIndex]: 条件格式规则索引 @@ -1470,6 +1503,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### clearRange([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1490,6 +1526,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### deleteRange(move [,setting]) +[todo] + + - **参数**: - {String} [move]: 删除后,右侧还是下方的单元格移动 @@ -1516,6 +1555,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### insertRange(move [,setting]) +[todo] + + - **参数**: - {String} [move]: 活动单元格右移或者下移 @@ -1549,6 +1591,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### matrixOperation(type [,setting]) +[todo] + + - **参数**: - {String} [type]: 矩阵操作的类型 @@ -1591,6 +1636,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### matrixCalculation(type, number [,setting]) +[todo] + + - **参数**: - {String} [type]: 计算方式 @@ -1633,6 +1681,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getAllSheets() +[todo] + + - **说明**: 返回所有工作表配置,格式同[工作表配置](/zh/guide/sheet.html),得到的结果可用于表格初始化时作为`options.data`使用。 @@ -1648,6 +1699,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getLuckysheetfile() +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1666,6 +1720,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getSheetData([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1679,6 +1736,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getConfig([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1692,6 +1752,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setConfig([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1706,6 +1769,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetAdd([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1726,6 +1792,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetDelete([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1745,6 +1814,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetCopy([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1765,6 +1837,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetHide([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1786,6 +1861,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetShow([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1805,6 +1883,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetActive(order [,setting]) +[todo] + + - **参数**: - {Number} [order]: 要激活的工作表索引 @@ -1824,6 +1905,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetName(name [,setting]) +[todo] + + - **参数**: - {String} [name]: 新的工作表名称 @@ -1844,6 +1928,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetColor(color [,setting]) +[todo] + + - **参数**: - {String} [color]: 工作表颜色 @@ -1864,6 +1951,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetMove(type [,setting]) +[todo] + + - **参数**: - {String | Number} [type]: 工作表移动方向或者移动的目标索引, @@ -1891,6 +1981,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setSheetOrder(orderList [,setting]) +[todo] + + - **参数**: - {Array} [orderList]: 工作表顺序,设置工作表的index和order来指定位置,如: @@ -1943,6 +2036,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### refresh([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1969,6 +2065,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getScreenshot([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -1983,6 +2082,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setWorkbookName(name [,setting]) +[todo] + + - **参数**: - {Number} [name]: 工作簿名称 @@ -1997,6 +2099,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### undo([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -2010,6 +2115,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### redo([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -2025,6 +2133,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### insertChart([setting]) +[todo] + + - **参数**: - {PlainObject} [setting]: 可选参数 @@ -2040,6 +2151,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### setChart(chartId, attr, value [,setting]) +[todo] + + - **参数**: - {String} [chartId]: 指定要修改的图表id @@ -2065,6 +2179,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### getChart(chartId) +[todo] + + - **参数**: - {String} [chartId]: 指定要获取的图表id @@ -2077,6 +2194,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### deleteChart(chartId [,setting]) +[todo] + + - **参数**: - {String} [chartId]: 要删除的图表id @@ -2094,6 +2214,9 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### transToCellData(data [,setting])
+[todo] + + - **参数**: - {Array} [data]: data数据 @@ -2109,6 +2232,8 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### transToData(celldata [,setting])
+[todo] + - **参数**: - {Array} [celldata]: data数据 @@ -2124,6 +2249,8 @@ Luckysheet针对常用的数据操作需求,开放了主要功能的API,开 ### toJson() +[todo] + - **说明**: 导出的json字符串可以直接当作`luckysheet.create(options)`初始化工作簿时的参数`options`使用,使用场景在用户自己操作表格后想要手动保存全部的参数,再去别处初始化这个表格使用,类似一个luckysheet专有格式的导入导出。 diff --git a/docs/zh/guide/sheet.md b/docs/zh/guide/sheet.md index 3417dc2..e16f3c0 100644 --- a/docs/zh/guide/sheet.md +++ b/docs/zh/guide/sheet.md @@ -41,6 +41,7 @@ options.data示例如下: "chart": [], //图表配置 "allowEdit": true, //是否允许编辑 "zoomRatio":1, // 缩放比例 + "image":[], //图片 }, { "name": "Sheet2", @@ -381,7 +382,10 @@ options.data示例如下: ### calcChain - 类型:Array - 默认值:[] -- 作用: 公式链,用于公式所链接的单元格改变后,所有引用此单元格的公式都会联动刷新 +- 作用: 公式链是一个由用户指定顺序排列的公式信息数组,Luckysheet会根据此顺序来决定公式执行的顺序。 + + 注意,在初始化工作簿的时候,如果有单元格包含公式,请务必添加对应单元格位置的公式链,否则Luckysheet无法识别公式。 + - 示例: ```js [{ @@ -1206,6 +1210,42 @@ options.data示例如下: - 作用: 此sheet页的缩放比例,为0~1之间的二位小数数字。比如`0.1`、`0.56` ------------ +### image +- 类型:Array +- 默认值:[] +- 作用: 插入表格中图片信息,包含图片地址、宽高、位置、裁剪等信息 +- 示例: + 以下为一个`imageItem`案例,通常一个工作表中可能存在多个图片,所以`image`的格式为数组`[imageItem,imageItem,...]` + ```json + { + type: '3', //1移动并调整单元格大小 2移动并且不调整单元格的大小 3不要移动单元格并调整其大小 + src: '', //图片url + originWidth: 1484, //图片原始宽度 + originHeight: 834, //图片原始高度 + default: { + width: 293, //图片 宽度 + height: 196, //图片 高度 + left: 409, //图片离表格左边的 位置 + top: 248, //图片离表格顶部的 位置 + }, + crop: { + width: 293, //图片裁剪后 宽度 + height: 196, //图片裁剪后 高度 + offsetLeft: 0, //图片裁剪后离未裁剪时 左边的位移 + offsetTop: 0, //图片裁剪后离未裁剪时 顶部的位移 + }, + isFixedPos: false, //固定位置 + fixedLeft: 507, //固定位置 左位移 + fixedTop: 141, //固定位置 右位移 + border: { + width: 0, //边框宽度 + radius: 0, //边框半径 + style: 'solid', //边框类型 + color: '#000', //边框颜色 + } + } + ``` +------------ ## 调试信息 diff --git a/src/core.js b/src/core.js index f0b6e89..897d765 100644 --- a/src/core.js +++ b/src/core.js @@ -37,7 +37,8 @@ import * as api from './global/api'; let luckysheet = {}; // mount api -luckysheet.api = api; +// luckysheet.api = api; +Object.assign(luckysheet, api); //创建luckysheet表格 luckysheet.create = function (setting) { diff --git a/src/function/functionlist.js b/src/function/functionlist.js index 00f2016..071636c 100644 --- a/src/function/functionlist.js +++ b/src/function/functionlist.js @@ -1,6 +1,5 @@ import functionImplementation from './functionImplementation'; import Store from '../store/index' - //{"0":"数学","1":"统计","2":"查找","3":"Luckysheet内置","4":"数据挖掘","5":"数据源","6":"日期","7":"过滤器","8":"财务","9":"工程计算","10":"逻辑","11":"运算符","12":"文本","13":"转换工具","14":"数组"} const functionlist_zh = [{ 'n': 'SUMIF', diff --git a/src/global/api.js b/src/global/api.js index 8363b0e..878f28d 100644 --- a/src/global/api.js +++ b/src/global/api.js @@ -20,6 +20,7 @@ import json from "./json"; import { orderbydata } from "./sort"; import editor from "./editor"; import { rowlenByRange } from "./getRowlen"; +import luckysheetformula from './formula' const IDCardReg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i; @@ -68,6 +69,9 @@ export function getCellValue(row, column, options = {}) { /** * 设置单元格的值 + * + * 关键点:如果设置了公式,则需要更新公式链insertUpdateFunctionGroup,如果设置了不是公式,判断之前是公式,则需要清除公式delFunctionGroup + * * @param {Number} row 单元格所在行数;从0开始的整数,0表示第一行 * @param {Number} column 单元格所在列数;从0开始的整数,0表示第一列 * @param {Object | String | Number} value 要设置的值;可以为字符串或数字,或为符合Luckysheet单元格格式的对象 @@ -75,6 +79,156 @@ export function getCellValue(row, column, options = {}) { * @param {Number} options.order 工作表索引;默认值为当前工作表索引 * @param {Function} options.success 操作结束的回调函数 */ +// export function setCellValue(row, column, value, options = {}) { +// if (row == null && column == null) { +// return console.error('Arguments row or column cannot be null or undefined.') +// } +// let curSheetOrder = getSheetIndex(Store.currentSheetIndex); +// let { +// order = curSheetOrder, +// success +// } = {...options} +// let targetSheetData = Store.luckysheetfile[order].data; +// let cell = targetSheetData[row][column]; +// let vupdate; + +// if (getObjType(value) == 'object') { +// cell = value; + +// if (getObjType(value.v) == 'object') { +// vupdate = vaule.v.v; +// } else { +// vupdate = value.v; +// } +// } else { +// vupdate = value; +// } + +// if (isRealNull(vupdate)) { +// if (getObjType(cell) == 'object') { +// delete cell.m; +// delete cell.v; +// } else { +// cell = null; +// } +// return; +// } + +// if (isRealNull(cell)) { +// cell = {} +// } + +// if (vupdate.toString().substring(0, 1) == "'") { +// cell.m = vupdate.toString().substring(1); +// cell.ct = { "fa": "@", "t": "s" }; +// cell.v = vupdate.toString().substring(1); +// } else if (vupdate.toString().toUpperCase() === 'TRUE') { +// cell.m = "TRUE"; +// cell.ct = { "fa": "General", "t": "b" }; +// cell.v = true; +// } else if (vupdate.toString().toUpperCase() === 'FALSE') { +// cell.m = "FALSE"; +// cell.ct = { "fa": "General", "t": "b" }; +// cell.v = false; +// } else if (valueIsError(vupdate)) { +// cell.m = vupdate.toString(); +// cell.ct = { "fa": "General", "t": "e" }; +// cell.v = vupdate; +// } else { +// if (cell.f != null && isRealNum(vupdate) && !IDCardReg.test(vupdate)) { +// cell.v = parseFloat(vupdate); +// if (cell.ct == null) { +// cell.ct = { +// 'fa': 'General', +// 't': 'n' +// } +// } + +// if (cell.v == Infinity || cell.v == -Infinity) { +// cell.m = cell.v.toString(); +// } else { +// if (cell.v.toString().indexOf('e') > -1) { +// let len = cell.v.toString().split('.')[1].split('e')[0].length; +// if (len > 5) { +// len = 5; +// } + +// cell.m = cell.v.toExponential(len).toString(); +// } else { +// let v_p = Math.round(cell.v * 1000000000) / 1000000000; +// if (cell.ct == null) { +// let mask = genarate(v_p); +// cell.m = mask[0].toString(); +// } else { +// let mask = update(cell.ct.fa, v_p); +// cell.m = mask.toString(); +// } +// } +// } +// } else if (cell.ct != null && cell.ct.fa == '@') { +// cell.m = vupdate.toString(); +// cell.v = vupdate; +// } else if (cell.ct != null && cell.ct.fa != null && cell.ct.fa != 'General') { +// if (isRealNum(vupdate)) { +// vupdate = parseFloat(vupdate); +// } + +// let mask = update(cell.ct.fa, vupdate); + +// if (mask === vupdate) {// 若原来单元格格式 应用不了 要更新的值,则获取更新值的 格式 +// mask = genarate(vupdate); + +// cell.m = mask[0].toString(); +// cell.ct = mask[1]; +// cell.v = mask[2]; +// } else { +// cell.m = mask.toString(); +// cell.v = vupdate; +// } +// } else { +// if (isRealNum(vupdate) && !IDCardReg.test(vupdate)) { +// vupdate = parseFloat(vupdate); +// cell.v = parseFloat(vupdate); +// cell.ct = { +// 'fa': 'General', +// 't': 'n' +// } +// if (cell.v == Infinity || cell.v == -Infinity) { +// cell.m = cell.v.toString(); +// } else { +// let mask = genarate(cell.v); +// cell.m = mask[0].toString(); +// } +// } else { +// let mask = genarate(vupdate); +// cell.m = mask[0].toString(); +// cell.ct = mask[1]; +// cell.v = mask[2]; +// } +// } +// } +// if (!server.allowUpdate && !luckysheetConfigsetting.pointEdit) { +// if (cell.ct != null && !/^(w|W)((0?)|(0\.0+))$/.test(cell.ct.fa) && cell.ct.t == 'n' && cell.v != null && parseInt(cell.v).toString().length > 4) { +// let autoFormatw = luckysheetConfigsetting.autoFormatw.toString().toUpperCase(); +// let accuracy = luckysheetConfigsetting.accuracy; +// let sfmt = setAccuracy(autoFormatw, accuracy); + +// if (sfmt != 'General') { +// cell.ct.fa = sfmt; +// cell.m = update(sfmt, cell.v); +// } +// } +// } +// // refresh +// jfrefreshgrid(targetSheetData, { +// row: [row], +// column: [column] +// }) + +// if (success && typeof success === 'function') { +// success(); +// } +// } export function setCellValue(row, column, value, options = {}) { if (row == null && column == null) { return console.error('Arguments row or column cannot be null or undefined.') @@ -84,142 +238,10 @@ export function setCellValue(row, column, value, options = {}) { order = curSheetOrder, success } = {...options} - let targetSheetData = Store.luckysheetfile[order].data; - let cell = targetSheetData[row][column]; - let vupdate; - - if (getObjType(value) == 'object') { - cell = value; - - if (getObjType(value.v) == 'object') { - vupdate = vaule.v.v; - } else { - vupdate = value.v; - } - } else { - vupdate = value; - } - - if (isRealNull(vupdate)) { - if (getObjType(cell) == 'object') { - delete cell.m; - delete cell.v; - } else { - cell = null; - } - return; - } - - if (isRealNull(cell)) { - cell = {} - } - - if (vupdate.toString().substring(0, 1) == "'") { - cell.m = vupdate.toString().substring(1); - cell.ct = { "fa": "@", "t": "s" }; - cell.v = vupdate.toString().substring(1); - } else if (vupdate.toString().toUpperCase() === 'TRUE') { - cell.m = "TRUE"; - cell.ct = { "fa": "General", "t": "b" }; - cell.v = true; - } else if (vupdate.toString().toUpperCase() === 'FALSE') { - cell.m = "FALSE"; - cell.ct = { "fa": "General", "t": "b" }; - cell.v = false; - } else if (valueIsError(vupdate)) { - cell.m = vupdate.toString(); - cell.ct = { "fa": "General", "t": "e" }; - cell.v = vupdate; - } else { - if (cell.f != null && isRealNum(vupdate) && !IDCardReg.test(vupdate)) { - cell.v = parseFloat(vupdate); - if (cell.ct == null) { - cell.ct = { - 'fa': 'General', - 't': 'n' - } - } - - if (cell.v == Infinity || cell.v == -Infinity) { - cell.m = cell.v.toString(); - } else { - if (cell.v.toString().indexOf('e') > -1) { - let len = cell.v.toString().split('.')[1].split('e')[0].length; - if (len > 5) { - len = 5; - } - - cell.m = cell.v.toExponential(len).toString(); - } else { - let v_p = Math.round(cell.v * 1000000000) / 1000000000; - if (cell.ct == null) { - let mask = genarate(v_p); - cell.m = mask[0].toString(); - } else { - let mask = update(cell.ct.fa, v_p); - cell.m = mask.toString(); - } - } - } - } else if (cell.ct != null && cell.ct.fa == '@') { - cell.m = vupdate.toString(); - cell.v = vupdate; - } else if (cell.ct != null && cell.ct.fa != null && cell.ct.fa != 'General') { - if (isRealNum(vupdate)) { - vupdate = parseFloat(vupdate); - } - - let mask = update(cell.ct.fa, vupdate); - - if (mask === vupdate) {// 若原来单元格格式 应用不了 要更新的值,则获取更新值的 格式 - mask = genarate(vupdate); - - cell.m = mask[0].toString(); - cell.ct = mask[1]; - cell.v = mask[2]; - } else { - cell.m = mask.toString(); - cell.v = vupdate; - } - } else { - if (isRealNum(vupdate) && !IDCardReg.test(vupdate)) { - vupdate = parseFloat(vupdate); - cell.v = parseFloat(vupdate); - cell.ct = { - 'fa': 'General', - 't': 'n' - } - if (cell.v == Infinity || cell.v == -Infinity) { - cell.m = cell.v.toString(); - } else { - let mask = genarate(cell.v); - cell.m = mask[0].toString(); - } - } else { - let mask = genarate(vupdate); - cell.m = mask[0].toString(); - cell.ct = mask[1]; - cell.v = mask[2]; - } - } - } - if (!server.allowUpdate && !luckysheetConfigsetting.pointEdit) { - if (cell.ct != null && !/^(w|W)((0?)|(0\.0+))$/.test(cell.ct.fa) && cell.ct.t == 'n' && cell.v != null && parseInt(cell.v).toString().length > 4) { - let autoFormatw = luckysheetConfigsetting.autoFormatw.toString().toUpperCase(); - let accuracy = luckysheetConfigsetting.accuracy; - let sfmt = setAccuracy(autoFormatw, accuracy); - - if (sfmt != 'General') { - cell.ct.fa = sfmt; - cell.m = update(sfmt, cell.v); - } - } - } - // refresh - jfrefreshgrid(targetSheetData, { - row: [row], - column: [column] - }) + + + luckysheetformula.updatecell(row, column, value); + if (success && typeof success === 'function') { success(); diff --git a/src/global/formula.js b/src/global/formula.js index 40c5e8d..c4f0955 100644 --- a/src/global/formula.js +++ b/src/global/formula.js @@ -1189,13 +1189,15 @@ const luckysheetformula = { "opacity": "0.13" }); }, - updatecell: function(r, c) { + updatecell: function(r, c, value) { let _this = this; - let $input = $("#luckysheet-rich-text-editor"), - value = $input.text(); + let $input = $("#luckysheet-rich-text-editor"); + + // API, we get value from user + value = value || $input.text(); - if (_this.rangetosheet != Store.currentSheetIndex) { + if (_this.rangetosheet != null && _this.rangetosheet != Store.currentSheetIndex) { sheetmanage.changeSheetExec(_this.rangetosheet); } @@ -1218,7 +1220,7 @@ const luckysheetformula = { } } - if (value.slice(0, 1) == "=" && value.length > 1) { + if (getObjType(value) == "string" && value.slice(0, 1) == "=" && value.length > 1) { } else if(getObjType(curv) == "object" && curv.ct != null && curv.ct.fa != null && curv.ct.fa != "@" && !isRealNull(value)){ @@ -1257,6 +1259,42 @@ const luckysheetformula = { } } } + // from API setCellValue,luckysheet.setCellValue(0, 0, {f: "=sum(D1)", bg:"#0188fb"}),value is an object, so get attribute f as value + else if(getObjType(value) == "object"){ + let valueFunction = value.f; + + if(getObjType(valueFunction) == "string" && valueFunction.slice(0, 1) == "=" && valueFunction.length > 1){ + let v = _this.execfunction(valueFunction, r, c, true); + + // get v/m/ct + curv = _this.execFunctionGroupData[r][c]; + + // get f + curv.f = v[2]; + + // get other cell style attribute + delete value.v; + delete value.m; + delete value.f; + Object.assign(curv,value); + + //打进单元格的sparklines的配置串, 报错需要单独处理。 + if(v.length == 4 && v[3].type == "sparklines"){ + delete curv.m; + delete curv.v; + + let curCalv = v[3].data; + + if(getObjType(curCalv) == "array" && getObjType(curCalv[0]) != "object"){ + curv.v = curCalv[0]; + } + else{ + curv.spl = v[3].data; + } + } + } + + } else{ _this.delFunctionGroup(r, c); _this.execFunctionGroup(r, c, value); @@ -1266,7 +1304,7 @@ const luckysheetformula = { delete curv.f; delete curv.spl; - if(curv.qp == 1 && value.substr(0,1)!="'"){//if quotePrefix is 1, cell is force string, cell clear quotePrefix when it is updated + if(curv.qp == 1 && ('' + value).substr(0,1)!="'"){//if quotePrefix is 1, cell is force string, cell clear quotePrefix when it is updated curv.qp = 0; if(curv.ct!=null){ curv.ct.fa = "General"; @@ -1298,6 +1336,36 @@ const luckysheetformula = { } } } + // from API setCellValue,luckysheet.setCellValue(0, 0, {f: "=sum(D1)", bg:"#0188fb"}),value is an object, so get attribute f as value + else if(getObjType(value) == "object"){ + let valueFunction = value.f; + + if(getObjType(valueFunction) == "string" && valueFunction.slice(0, 1) == "=" && valueFunction.length > 1){ + let v = _this.execfunction(valueFunction, r, c, true); + + // value = { + // "v": v[1], + // "f": v[2] + // }; + + // update attribute v + value.v = v[1]; + value.f = v[2]; + + //打进单元格的sparklines的配置串, 报错需要单独处理。 + if(v.length == 4 && v[3].type == "sparklines"){ + let curCalv = v[3].data; + + if(getObjType(curCalv) == "array" && getObjType(curCalv[0]) != "object"){ + value.v = curCalv[0]; + } + else{ + value.spl = v[3].data; + } + } + } + + } else{ _this.delFunctionGroup(r, c); _this.execFunctionGroup(r, c, value); @@ -1305,6 +1373,7 @@ const luckysheetformula = { } } + // value maybe an object setcellvalue(r, c, d, value); _this.cancelNormalSelected(); @@ -4451,6 +4520,7 @@ const luckysheetformula = { this.execFunctionGroup(); } }, + // When set origin_r and origin_c, that mean just refresh cell value link to [origin_r,origin_c] cell execFunctionGroup: function(origin_r, origin_c, value, index, data, isForce=false) { let _this = this; From 586e33089bdcb79e72714fd7c65db160c96979f7 Mon Sep 17 00:00:00 2001 From: lrz <1414556676@qq.com> Date: Fri, 11 Sep 2020 21:42:52 +0800 Subject: [PATCH 08/19] docs(png error): pic error pic error --- docs/guide/README.md | 4 ++-- docs/zh/guide/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guide/README.md b/docs/guide/README.md index 52edfdb..4997c9f 100644 --- a/docs/guide/README.md +++ b/docs/guide/README.md @@ -6,7 +6,7 @@ Luckysheet is an online spreadsheet like excel that is powerful, simple to confi ## Demo [Online demo](https://mengshukeji.github.io/LuckysheetDemo/) -![Demo](/img/LuckysheetDemo.gif) +![Demo](/LuckysheetDocs/img/LuckysheetDemo.gif) ## Features @@ -153,7 +153,7 @@ An example of a Luckysheet file is as follows, the table contains 3 sheets:` luckysheetfile = [{sheet1 settings}, {sheet2 settings}, {sheet3 settings}]` Equivalent to 3 sheets of excel -![excel sheet](/docs/.vuepress/public/img/excel.png) +![excel sheet](/LuckysheetDocs/img/excel.png) An example of a sheet in the file is as follows: ```javascript diff --git a/docs/zh/guide/README.md b/docs/zh/guide/README.md index ec7089a..8d0f36b 100644 --- a/docs/zh/guide/README.md +++ b/docs/zh/guide/README.md @@ -6,7 +6,7 @@ Luckysheet ,一款纯前端类似excel的在线表格,功能强大、配置 ## Demo [在线demo](https://mengshukeji.github.io/LuckysheetDemo/) -![演示](/img/LuckysheetDemo.gif) +![演示](/LuckysheetDocs/img/LuckysheetDemo.gif) ## 特性 @@ -153,7 +153,7 @@ npm run build luckysheetfile = [ {sheet1设置}, {sheet2设置}, {sheet3设置} ]` 相当于excel的3个sheet -![excel sheet](/img/excel.png) +![excel sheet](/LuckysheetDocs/img/excel.png) 文件中的一个sheet的数据`luckysheetfile[0]`的结构如下: ```json From 8c9953666a099e7ff707a99e7f550fa729396db3 Mon Sep 17 00:00:00 2001 From: liuyang Date: Fri, 11 Sep 2020 21:53:09 +0800 Subject: [PATCH 09/19] perf(rewrite draw canvas method): prepare for inline string suport complex rotate and wrap --- src/controllers/menuButton.js | 6 +- src/global/draw.js | 1190 +++++---------------------------- src/global/getRowlen.js | 380 +++++++---- src/store/index.js | 1 + 4 files changed, 440 insertions(+), 1137 deletions(-) diff --git a/src/controllers/menuButton.js b/src/controllers/menuButton.js index c09bc92..7b9e046 100644 --- a/src/controllers/menuButton.js +++ b/src/controllers/menuButton.js @@ -2937,9 +2937,9 @@ const menuButton = { d[r][c][attr] = foucsStatus; } - if(attr == "tr" && d[r][c].tb != null){ - d[r][c].tb = "0"; - } + // if(attr == "tr" && d[r][c].tb != null){ + // d[r][c].tb = "0"; + // } } } } diff --git a/src/global/draw.js b/src/global/draw.js index 3dc866e..d717dd6 100644 --- a/src/global/draw.js +++ b/src/global/draw.js @@ -996,6 +996,7 @@ function luckysheetDrawMain(scrollWidth, scrollHeight, drawWidth, drawHeight, of Store.measureTextCacheTimeOut = setTimeout(() => { Store.measureTextCache = {}; + Store.measureTextCellInfoCache = {}; }, 2000); } @@ -1178,7 +1179,7 @@ let nullCellRender = function(r, c, start_r, start_c, end_r, end_c,luckysheetTab } -let cellRender1 = function(r, c, start_r, start_c, end_r, end_c, value, luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05,isMerge){ +let cellRender = function(r, c, start_r, start_c, end_r, end_c, value, luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05,isMerge){ let cell = Store.flowdata[r][c]; let cellWidth = end_c - start_c - 2; @@ -1273,7 +1274,7 @@ let cellRender1 = function(r, c, start_r, start_c, end_r, end_c, value, luckyshe if(cell.tb == '1' && cellOverflow_colInObj.colIn){ //此单元格 为 溢出单元格渲染范围最后一列,绘制溢出单元格内容 if(cellOverflow_colInObj.colLast){ - cellTextRender( + cellOverflowRender( cellOverflow_colInObj.rowIndex, cellOverflow_colInObj.colIndex, cellOverflow_colInObj.stc, @@ -1504,7 +1505,9 @@ let cellRender1 = function(r, c, start_r, start_c, end_r, end_c, value, luckyshe cellWidth:cellWidth, cellHeight:cellHeight, space_width:space_width, - space_height:space_height + space_height:space_height, + r:r, + c:c }); //若单元格有条件格式图标集 @@ -1599,1042 +1602,213 @@ let cellRender1 = function(r, c, start_r, start_c, end_r, end_c, value, luckyshe } } -//非空白单元格渲染 -let cellRender = function(r, c, start_r, start_c, end_r, end_c, value, luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05,isMerge){ +//溢出单元格渲染 +let cellOverflowRender = function(r, c, stc, edc,luckysheetTableContent,scrollHeight,scrollWidth,offsetLeft,offsetTop,af_compute, cf_compute){ + //溢出单元格 起止行列坐标 + let start_r; + if (r == 0) { + start_r = -scrollHeight - 1; + } + else { + start_r = Store.visibledatarow[r - 1] - scrollHeight - 1; + } + + let end_r = Store.visibledatarow[r] - scrollHeight; + + let start_c; + if (stc == 0) { + start_c = -scrollWidth; + } + else { + start_c = Store.visibledatacolumn[stc - 1] - scrollWidth; + } + + let end_c = Store.visibledatacolumn[edc] - scrollWidth; + // let cell = Store.flowdata[r][c]; let cellWidth = end_c - start_c - 2; let cellHeight = end_r - start_r - 2; let space_width = 2, space_height = 2; //宽高方向 间隙 + let pos_x = start_c + offsetLeft; + let pos_y = start_r + offsetTop + 1; + let fontset = luckysheetfontformat(cell); luckysheetTableContent.font = fontset; - // luckysheetTableContent.textBaseline = 'top'; + + luckysheetTableContent.save(); + luckysheetTableContent.beginPath(); + luckysheetTableContent.rect(pos_x , pos_y, cellWidth , cellHeight ); + luckysheetTableContent.clip(); + luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio); - //水平对齐 - let horizonAlign = menuButton.checkstatus(Store.flowdata, r, c, "ht"); - //垂直对齐 - let verticalAlign = menuButton.checkstatus(Store.flowdata, r, c, "vt"); - //文本单行 宽度和高度 - let measureText = getMeasureText(value, luckysheetTableContent); - //luckysheetTableContent.measureText(value); - let textMetrics = measureText.width; - let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent; + let textInfo = getCellTextInfo(cell , luckysheetTableContent, { + cellWidth:cellWidth, + cellHeight:cellHeight, + space_width:space_width, + space_height:space_height, + r:r, + c:c + }); + //交替颜色 let checksAF = alternateformat.checksAF(r, c, af_compute); //条件格式 let checksCF = conditionformat.checksCF(r, c, cf_compute); - //单元格 背景颜色 - let fillStyle = menuButton.checkstatus(Store.flowdata, r, c, "bg"); - if(checksAF != null && checksAF[1] != null){ //若单元格有交替颜色 背景颜色 - fillStyle = checksAF[1]; + //单元格 文本颜色 + luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , "fc"); + + //若单元格有交替颜色 文本颜色 + if(checksAF != null && checksAF[0] != null){ + luckysheetTableContent.fillStyle = checksAF[0]; } - if(checksCF != null && checksCF["cellColor"] != null){ //若单元格有条件格式 背景颜色 - fillStyle = checksCF["cellColor"]; + //若单元格有条件格式 文本颜色 + if(checksCF != null && checksCF["textColor"] != null){ + luckysheetTableContent.fillStyle = checksCF["textColor"]; } - if(fillStyle==null){ - luckysheetTableContent.fillStyle = "#FFFFFF"; - } - else{ - luckysheetTableContent.fillStyle = fillStyle; - } + cellTextRender( + textInfo, + luckysheetTableContent, + { + pos_x:pos_x, + pos_y:pos_y, + } + ); + luckysheetTableContent.restore(); + // let fontset = luckysheetfontformat(cell); + // luckysheetTableContent.font = fontset; + // // luckysheetTableContent.textBaseline = 'top'; + + // //溢出单元格 值 + // let value = getcellvalue(r, c, null, "m"); + // if(value == null){ + // value = getcellvalue(r, c); + // } + + // //文本单行 宽度和高度 + // let measureText = getMeasureText(value, luckysheetTableContent); + // //luckysheetTableContent.measureText(value); + // let textMetrics = measureText.width; + // let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent; + + // let pos_x = start_c + offsetLeft; + // let pos_y = start_r + offsetTop + 1; - let borderfix = menuButton.borderfix(Store.flowdata, r, c); - // console.log(value, fillStyle,borderfix); - let cellsize = [ - (start_c + offsetLeft + borderfix[0]), - (start_r + offsetTop + borderfix[1]), - (end_c - start_c + borderfix[2]-(!!isMerge?1:0)), - (end_r - start_r + borderfix[3]) - ]; - luckysheetTableContent.fillRect(cellsize[0], cellsize[1], cellsize[2], cellsize[3]); + // luckysheetTableContent.save(); + // luckysheetTableContent.beginPath(); + // luckysheetTableContent.rect(pos_x, pos_y, cellWidth, cellHeight); + // luckysheetTableContent.clip(); + // luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio); + + // //溢出单元格 水平对齐 + // let horizonAlign = menuButton.checkstatus(Store.flowdata, r, c, "ht"); + // let horizonAlignPos = (pos_x + space_width) ; //默认为1,左对齐 + // if(horizonAlign == "0"){ //居中对齐 + // horizonAlignPos = (pos_x + cellWidth / 2) - (textMetrics / 2); + // } + // else if(horizonAlign == "2"){ //右对齐 + // horizonAlignPos = (pos_x + cellWidth - space_width) - textMetrics; + // } + + // let verticalCellHeight = cellHeight>oneLineTextHeight?cellHeight:oneLineTextHeight; + // //溢出单元格 垂直对齐 + // let verticalAlign = menuButton.checkstatus(Store.flowdata, r, c, "vt"); + // let verticalAlignPos = (pos_y + verticalCellHeight - space_height) - oneLineTextHeight; //默认为2,下对齐 + // let verticalAlignPos_text = (pos_y + verticalCellHeight - space_height) ; //文本垂直方向基准线 + // luckysheetTableContent.textBaseline = "bottom"; + // if(verticalAlign == "0"){ //居中对齐 + // verticalAlignPos = (pos_y + verticalCellHeight / 2) - (oneLineTextHeight / 2); + + // verticalAlignPos_text = (pos_y + verticalCellHeight / 2) ; + // luckysheetTableContent.textBaseline = "middle"; + // } + // else if(verticalAlign == "1"){ //上对齐 + // verticalAlignPos = (pos_y + space_height) ; + + // verticalAlignPos_text = (pos_y + space_height) ; + // luckysheetTableContent.textBaseline = "top"; + // } - // luckysheetTableContent.fillRect( - // (start_c + offsetLeft - 1) , - // (start_r + offsetTop) , - // (end_c - start_c) , - // (end_r - start_r) - // ) + // verticalAlignPos = verticalAlignPos/Store.zoomRatio; + // horizonAlignPos = horizonAlignPos/Store.zoomRatio; + // verticalAlignPos_text = verticalAlignPos_text/Store.zoomRatio; - //若单元格有批注(单元格右上角红色小三角标示) - if(cell.ps != null){ - let ps_w = 8*Store.zoomRatio, ps_h = 8*Store.zoomRatio; //红色小三角宽高 + // //交替颜色 + // let checksAF = alternateformat.checksAF(r, c, af_compute); + // //条件格式 + // let checksCF = conditionformat.checksCF(r, c, cf_compute); - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - (end_c + offsetLeft - ps_w), - (start_r + offsetTop) - ); - luckysheetTableContent.lineTo( - (end_c + offsetLeft), - (start_r + offsetTop) - ); - luckysheetTableContent.lineTo( - (end_c + offsetLeft), - (start_r + offsetTop + ps_h) - ); - luckysheetTableContent.fillStyle = "#FC6666"; - luckysheetTableContent.fill(); - luckysheetTableContent.closePath(); - } + // //单元格 文本颜色 + // luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , "fc"); + + // //若单元格有交替颜色 文本颜色 + // if(checksAF != null && checksAF[0] != null){ + // luckysheetTableContent.fillStyle = checksAF[0]; + // } + // //若单元格有条件格式 文本颜色 + // if(checksCF != null && checksCF["textColor"] != null){ + // luckysheetTableContent.fillStyle = checksCF["textColor"]; + // } + + // luckysheetTableContent.fillText(value == null ? "" : value, horizonAlignPos, verticalAlignPos_text); + + // luckysheetTableContent.restore(); + + //单元格是否有删除线 + // let cl = menuButton.checkstatus(Store.flowdata, r, c , "cl"); + // if(cl == "1" && !isRealNull(value)){ + // luckysheetTableContent.beginPath(); + // luckysheetTableContent.strokeStyle = "#000"; + // luckysheetTableContent.moveTo( + // horizonAlignPos, + // verticalAlignPos + oneLineTextHeight / 2/Store.zoomRatio + // ); + // luckysheetTableContent.lineTo( + // horizonAlignPos + textMetrics/Store.zoomRatio, + // verticalAlignPos + oneLineTextHeight / 2/Store.zoomRatio + // ); + // luckysheetTableContent.stroke(); + // luckysheetTableContent.closePath(); + // } +} - //若单元格强制为字符串,则显示绿色小三角 - if(cell.qp==1 && isRealNum(cell.v)){ - let ps_w = 6*Store.zoomRatio, ps_h = 6*Store.zoomRatio; //红色小三角宽高 +//获取表格渲染范围 溢出单元格 +function getCellOverflowMap(canvas, col_st, col_ed, row_st, row_end){ + let map = {}; - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - (start_c + offsetLeft + ps_w-1), - (start_r + offsetTop) - ); - luckysheetTableContent.lineTo( - (start_c + offsetLeft-1), - (start_r + offsetTop) - ); - luckysheetTableContent.lineTo( - (start_c + offsetLeft-1), - (start_r + offsetTop + ps_h) - ); - luckysheetTableContent.fillStyle = "#487f1e"; - luckysheetTableContent.fill(); - luckysheetTableContent.closePath(); - } + let data = Store.flowdata; - //溢出单元格 - let cellOverflow_bd_r_render = true; //溢出单元格右边框是否需要绘制 - let cellOverflow_colInObj = cellOverflow_colIn(cellOverflowMap, r, c, dataset_col_st, dataset_col_ed); + for(let r = row_st; r <= row_end; r++){ + for(let c = 0; c < data[r].length; c++){ + let cell = data[r][c]; - if(cell.tb == '1' && cellOverflow_colInObj.colIn){ - //此单元格 为 溢出单元格渲染范围最后一列,绘制溢出单元格内容 - if(cellOverflow_colInObj.colLast){ - cellOverflowRender( - cellOverflow_colInObj.rowIndex, - cellOverflow_colInObj.colIndex, - cellOverflow_colInObj.stc, - cellOverflow_colInObj.edc, - luckysheetTableContent, - scrollHeight, - scrollWidth,offsetLeft,offsetTop,af_compute, cf_compute - ); - } - else{ - cellOverflow_bd_r_render = false; - } - } - //非溢出单元格 - else{ - //若单元格有条件格式数据条 - if(checksCF != null && checksCF["dataBar"] != null){ - let x = (start_c + offsetLeft + space_width); - let y = (start_r + offsetTop + space_height); - let w = (cellWidth - space_width * 2); - let h = (cellHeight - space_height * 2); + if (Store.config["colhidden"] != null && Store.config["colhidden"][c] != null) { + continue + } - let valueType = checksCF["dataBar"]["valueType"]; - let valueLen = checksCF["dataBar"]["valueLen"]; - let format = checksCF["dataBar"]["format"]; + if(cell != null && !isRealNull(cell.v) && cell.mc == null && cell.tb == '1'){ + // let fontset = luckysheetfontformat(cell); + // canvas.font = fontset; - if(valueType == 'minus'){ - //负数 - let minusLen = checksCF["dataBar"]["minusLen"]; - - if(format.length > 1){ - //渐变 - let my_gradient = luckysheetTableContent.createLinearGradient( - x + w * minusLen * (1 - valueLen), - y, - x + w * minusLen, - y - ); - my_gradient.addColorStop(0, "#ffffff"); - my_gradient.addColorStop(1, "#ff0000"); + //水平对齐 + let horizonAlign = menuButton.checkstatus(data, r, c, "ht"); - luckysheetTableContent.fillStyle = my_gradient; - } - else{ - //单色 - luckysheetTableContent.fillStyle = "#ff0000"; - } + //文本宽度 + // let value = getcellvalue(r, c, null, "m"); + // if(value == null){ + // value = getcellvalue(r, c); + // } - luckysheetTableContent.fillRect( - x + w * minusLen * (1 - valueLen), - y, - w * minusLen * valueLen, - h - ); - - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - x + w * minusLen * (1 - valueLen), - y - ); - luckysheetTableContent.lineTo( - x + w * minusLen * (1 - valueLen), - y + h - ); - luckysheetTableContent.lineTo( - x + w * minusLen, - y + h - ); - luckysheetTableContent.lineTo( - x + w * minusLen, - y - ); - luckysheetTableContent.lineTo( - x + w * minusLen * (1 - valueLen), - y - ); - luckysheetTableContent.lineWidth = 1; - luckysheetTableContent.strokeStyle = "#ff0000"; - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - else if(valueType == 'plus'){ - //正数 - let plusLen = checksCF["dataBar"]["plusLen"]; - - if(plusLen == 1){ - if(format.length > 1){ - //渐变 - let my_gradient = luckysheetTableContent.createLinearGradient( - x, - y, - x + w * valueLen, - y - ); - my_gradient.addColorStop(0, format[0]); - my_gradient.addColorStop(1, format[1]); - - luckysheetTableContent.fillStyle = my_gradient; - } - else{ - //单色 - luckysheetTableContent.fillStyle = format[0]; - } - - luckysheetTableContent.fillRect( - x, - y, - w * valueLen, - h - ); - - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - x, - y - ); - luckysheetTableContent.lineTo( - x, - y + h - ); - luckysheetTableContent.lineTo( - x + w * valueLen, - y + h - ); - luckysheetTableContent.lineTo( - x + w * valueLen, - y - ); - luckysheetTableContent.lineTo( - x, - y - ); - luckysheetTableContent.lineWidth = 1; - luckysheetTableContent.strokeStyle = format[0]; - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - else{ - let minusLen = checksCF["dataBar"]["minusLen"]; - - if(format.length > 1){ - //渐变 - let my_gradient = luckysheetTableContent.createLinearGradient( - x + w * minusLen, - y, - x + w * minusLen + w * plusLen * valueLen, - y - ); - my_gradient.addColorStop(0, format[0]); - my_gradient.addColorStop(1, format[1]); - - luckysheetTableContent.fillStyle = my_gradient; - } - else{ - //单色 - luckysheetTableContent.fillStyle = format[0]; - } - - luckysheetTableContent.fillRect( - x + w * minusLen, - y, - w * plusLen * valueLen, - h - ); - - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - x + w * minusLen, - y - ); - luckysheetTableContent.lineTo( - x + w * minusLen, - y + h - ); - luckysheetTableContent.lineTo( - x + w * minusLen + w * plusLen * valueLen, - y + h - ); - luckysheetTableContent.lineTo( - x + w * minusLen + w * plusLen * valueLen, - y - ); - luckysheetTableContent.lineTo( - x + w * minusLen, - y - ); - luckysheetTableContent.lineWidth = 1; - luckysheetTableContent.strokeStyle = format[0]; - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - } - } - - let pos_x = start_c + offsetLeft; - let pos_y = start_r + offsetTop + 1; - - luckysheetTableContent.save(); - luckysheetTableContent.beginPath(); - luckysheetTableContent.rect(pos_x , pos_y, cellWidth , cellHeight ); - luckysheetTableContent.clip(); - luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio); - - let horizonAlignPos = (pos_x + space_width) ; //默认为1,左对齐 - if(horizonAlign == "0"){ //居中对齐 - horizonAlignPos = (pos_x + cellWidth / 2) - (textMetrics / 2); - } - else if(horizonAlign == "2"){ //右对齐 - horizonAlignPos = (pos_x + cellWidth - space_width) - textMetrics; - } - - let verticalCellHeight = cellHeight>oneLineTextHeight?cellHeight:oneLineTextHeight; - - let verticalAlignPos = (pos_y + verticalCellHeight - space_height) - oneLineTextHeight; //默认为2,下对齐 - let verticalAlignPos_text = (pos_y + verticalCellHeight - space_height) ; //文本垂直方向基准线 - luckysheetTableContent.textBaseline = "bottom"; - if(verticalAlign == "0"){ //居中对齐 - verticalAlignPos = (pos_y + verticalCellHeight / 2) - (oneLineTextHeight / 2); - - verticalAlignPos_text = (pos_y + verticalCellHeight / 2) ; - luckysheetTableContent.textBaseline = "middle"; - } - else if(verticalAlign == "1"){ //上对齐 - verticalAlignPos = (pos_y + space_height) ; - - verticalAlignPos_text = (pos_y + space_height) ; - luckysheetTableContent.textBaseline = "top"; - } - - verticalAlignPos = verticalAlignPos/Store.zoomRatio; - horizonAlignPos = horizonAlignPos/Store.zoomRatio; - verticalAlignPos_text = verticalAlignPos_text/Store.zoomRatio; - // pos_x = pos_x/Store.zoomRatio; - // pos_y = pos_y/Store.zoomRatio; - // space_width = space_width/Store.zoomRatio; - // cellHeight = cellHeight/Store.zoomRatio; - // oneLineTextHeight = oneLineTextHeight/Store.zoomRatio; - - //若单元格有条件格式图标集 - if(checksCF != null && checksCF["icons"] != null){ - let l = checksCF["icons"]["left"]; - let t = checksCF["icons"]["top"]; - - luckysheetTableContent.drawImage( - luckysheet_CFiconsImg, - l * 42, - t * 32, - 32, - 32, - pos_x/Store.zoomRatio , - verticalAlignPos, - oneLineTextHeight/Store.zoomRatio, - oneLineTextHeight/Store.zoomRatio - ); - - if(horizonAlign != "0" && horizonAlign != "2"){ //左对齐时 文本渲染空出一个图标的距离 - horizonAlignPos = horizonAlignPos + oneLineTextHeight/Store.zoomRatio; - } - } - - //单元格 文本颜色 - luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , "fc"); - - //若单元格有交替颜色 文本颜色 - if(checksAF != null && checksAF[0] != null){ - luckysheetTableContent.fillStyle = checksAF[0]; - } - //若单元格有条件格式 文本颜色 - if(checksCF != null && checksCF["textColor"] != null){ - luckysheetTableContent.fillStyle = checksCF["textColor"]; - } - - //单元格是否有删除线 - let cl = menuButton.checkstatus(Store.flowdata, r, c , "cl"); - - if(cell.tb == '2'){ - //自动换行 - // luckysheetTableContent.textBaseline = 'top'; //textBaseline以top计算 - //Text rotation,0: 0、1: 45 、2: -45、3 Vertical text、4: 90 、5: -90, - if(cell.ct!=null && cell.ct.t=="inlineStr" && cell.ct.sharedStrings!=null && cell.ct.sharedStrings.length>0){ - let strArr = [],lineMaxHeight=[]; - let sharedStrings = cell.ct.sharedStrings; - for(let i=0;i 1){ - vArr = value.split(""); - } - else{ - vArr.push(value); - } - - let textW_all = 0; //拆分后宽高度合计 - let textH_all = 0; - - for(let i = 0; i < vArr.length; i++){ - let textW = getMeasureText(vArr[i], luckysheetTableContent).width; - //luckysheetTableContent.measureText(vArr[i]).width; - let textH = oneLineTextHeight; - - // textW /= Store.zoomRatio; - // textH /= Store.zoomRatio; - - textW_all += textW/Store.zoomRatio; - textH_all += textH/Store.zoomRatio; - - let hAP = (pos_x + space_width) ; - if(horizonAlign == "0"){ - hAP = (pos_x + cellWidth / 2) - (textW / 2); - } - else if(horizonAlign == "2"){ - hAP = (pos_x + cellWidth - space_width) - textW; - } - - let vAP = (pos_y + cellHeight - space_height) - textH * vArr.length; - if(verticalAlign == "0"){ - vAP = (pos_y + cellHeight / 2) - (textH / 2) * vArr.length; - } - else if(verticalAlign == "1"){ - vAP = (pos_y + space_height) ; - } - - hAP = hAP / Store.zoomRatio; - vAP = vAP / Store.zoomRatio; - - luckysheetTableContent.fillText(vArr[i], hAP, (vAP + i * textH/Store.zoomRatio)); - } - - if(cl == "1" && !isRealNull(value)){ - let textW = textW_all / vArr.length; - let textH = textH_all; - - let hAP = (pos_x + space_width) ; - if(horizonAlign == "0"){ - hAP = (pos_x + cellWidth / 2) - (textW / 2); - } - else if(horizonAlign == "2"){ - hAP = (pos_x + cellWidth - space_width) - textW; - } - - let vAP = (pos_y + cellHeight - space_height) - textH; - if(verticalAlign == "0"){ - vAP = (pos_y + cellHeight / 2) - (textH / 2); - } - else if(verticalAlign == "1"){ - vAP = (pos_y + space_height) ; - } - - hAP = hAP / Store.zoomRatio; - vAP = vAP / Store.zoomRatio; - - luckysheetTableContent.beginPath(); - luckysheetTableContent.strokeStyle = "#000"; - luckysheetTableContent.moveTo( - hAP + textW / 2, - vAP - ); - luckysheetTableContent.lineTo( - hAP + textW / 2, - vAP + textH - ); - luckysheetTableContent.closePath(); - luckysheetTableContent.stroke(); - } - } - } - else if(cell.tr == "4" || cell.tr == "5"){ - let textW = oneLineTextHeight; - let textH = textMetrics; - - let hAP = (pos_x + space_width) ; - if(horizonAlign == "0"){ - hAP = (pos_x + cellWidth / 2) - (textW / 2); - } - else if(horizonAlign == "2"){ - hAP = (pos_x + cellWidth - space_width) - textW; - } - - let vAP = (pos_y + cellHeight - space_height) - textH; - if(verticalAlign == "0"){ - vAP = (pos_y + cellHeight / 2) - (textH / 2); - } - else if(verticalAlign == "1"){ - vAP = (pos_y + space_height) ; - } - - hAP = hAP / Store.zoomRatio; - vAP = vAP / Store.zoomRatio; - - //向下90(90 旋转) - if(tr == "4"){ - luckysheetTableContent.save(); - luckysheetTableContent.translate(hAP, vAP); - luckysheetTableContent.rotate(90 * Math.PI / 180); - luckysheetTableContent.translate(-hAP, -vAP); - luckysheetTableContent.fillText(value == null ? "" : value, hAP, vAP - textW/ Store.zoomRatio); - luckysheetTableContent.restore(); - } - - //向上90(-90 旋转) - if(tr == "5"){ - luckysheetTableContent.save(); - luckysheetTableContent.translate(hAP + textH/ Store.zoomRatio, vAP); - luckysheetTableContent.rotate(-90 * Math.PI / 180); - luckysheetTableContent.translate(-(hAP + textH/ Store.zoomRatio), -vAP); - luckysheetTableContent.fillText(value == null ? "" : value, hAP, vAP - textH/ Store.zoomRatio); - luckysheetTableContent.restore(); - } - - if(cl == "1" && !isRealNull(value)){ - luckysheetTableContent.beginPath(); - luckysheetTableContent.strokeStyle = "#000"; - luckysheetTableContent.moveTo(hAP + textW/ Store.zoomRatio / 2, vAP); - luckysheetTableContent.lineTo(hAP + textW/ Store.zoomRatio / 2, vAP + textH/ Store.zoomRatio); - luckysheetTableContent.closePath(); - luckysheetTableContent.stroke(); - } - } - } - else{ - //单元格有下钻属性,文本颜色变成超链接的颜色 - if(cell.dd != null){ - luckysheetTableContent.fillStyle = "#0000ff"; - - luckysheetTableContent.beginPath(); - luckysheetTableContent.strokeStyle = "#0000ff"; - luckysheetTableContent.moveTo( - horizonAlignPos, - verticalAlignPos + oneLineTextHeight - ); - luckysheetTableContent.lineTo( - horizonAlignPos + textMetrics, - verticalAlignPos + oneLineTextHeight - ); - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - - luckysheetTableContent.fillText(value == null ? "" : value, horizonAlignPos, verticalAlignPos_text); - - if(cl == "1" && !isRealNull(value)){ - luckysheetTableContent.beginPath(); - luckysheetTableContent.strokeStyle = "#000"; - luckysheetTableContent.moveTo( - horizonAlignPos, - verticalAlignPos + oneLineTextHeight / 2 / Store.zoomRatio - ); - luckysheetTableContent.lineTo( - horizonAlignPos + textMetrics/ Store.zoomRatio, - verticalAlignPos + oneLineTextHeight / 2 / Store.zoomRatio - ); - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - } - - luckysheetTableContent.restore(); - } - - if(cellOverflow_bd_r_render){ - //右边框 - if(!Store.luckysheetcurrentisPivotTable && !fillStyle && Store.showGridLines){ - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - (end_c + offsetLeft - 2 + bodrder05), - (start_r + offsetTop) - ); - luckysheetTableContent.lineTo( - (end_c + offsetLeft - 2 + bodrder05), - (end_r + offsetTop) - ); - luckysheetTableContent.lineWidth = 1; - luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle; - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } - } - - //下边框 - if(!Store.luckysheetcurrentisPivotTable && !fillStyle && Store.showGridLines){ - luckysheetTableContent.beginPath(); - luckysheetTableContent.moveTo( - (start_c + offsetLeft - 1), - (end_r + offsetTop - 2 + bodrder05) - ); - luckysheetTableContent.lineTo( - (end_c + offsetLeft - 1), - (end_r + offsetTop - 2 + bodrder05) - ); - luckysheetTableContent.lineWidth = 1; - luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle; - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } -} - -//溢出单元格渲染 -let cellOverflowRender = function(r, c, stc, edc,luckysheetTableContent,scrollHeight,scrollWidth,offsetLeft,offsetTop,af_compute, cf_compute){ - //溢出单元格 起止行列坐标 - let start_r; - if (r == 0) { - start_r = -scrollHeight - 1; - } - else { - start_r = Store.visibledatarow[r - 1] - scrollHeight - 1; - } - - let end_r = Store.visibledatarow[r] - scrollHeight; - - let start_c; - if (stc == 0) { - start_c = -scrollWidth; - } - else { - start_c = Store.visibledatacolumn[stc - 1] - scrollWidth; - } - - let end_c = Store.visibledatacolumn[edc] - scrollWidth; - - // - let cell = Store.flowdata[r][c]; - let cellWidth = end_c - start_c - 2; - let cellHeight = end_r - start_r - 2; - let space_width = 2, space_height = 2; //宽高方向 间隙 - - let fontset = luckysheetfontformat(cell); - luckysheetTableContent.font = fontset; - // luckysheetTableContent.textBaseline = 'top'; - - //溢出单元格 值 - let value = getcellvalue(r, c, null, "m"); - if(value == null){ - value = getcellvalue(r, c); - } - - //文本单行 宽度和高度 - let measureText = getMeasureText(value, luckysheetTableContent); - //luckysheetTableContent.measureText(value); - let textMetrics = measureText.width; - let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent; - - let pos_x = start_c + offsetLeft; - let pos_y = start_r + offsetTop + 1; - - luckysheetTableContent.save(); - luckysheetTableContent.beginPath(); - luckysheetTableContent.rect(pos_x, pos_y, cellWidth, cellHeight); - luckysheetTableContent.clip(); - luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio); - - //溢出单元格 水平对齐 - let horizonAlign = menuButton.checkstatus(Store.flowdata, r, c, "ht"); - let horizonAlignPos = (pos_x + space_width) ; //默认为1,左对齐 - if(horizonAlign == "0"){ //居中对齐 - horizonAlignPos = (pos_x + cellWidth / 2) - (textMetrics / 2); - } - else if(horizonAlign == "2"){ //右对齐 - horizonAlignPos = (pos_x + cellWidth - space_width) - textMetrics; - } - - let verticalCellHeight = cellHeight>oneLineTextHeight?cellHeight:oneLineTextHeight; - //溢出单元格 垂直对齐 - let verticalAlign = menuButton.checkstatus(Store.flowdata, r, c, "vt"); - let verticalAlignPos = (pos_y + verticalCellHeight - space_height) - oneLineTextHeight; //默认为2,下对齐 - let verticalAlignPos_text = (pos_y + verticalCellHeight - space_height) ; //文本垂直方向基准线 - luckysheetTableContent.textBaseline = "bottom"; - if(verticalAlign == "0"){ //居中对齐 - verticalAlignPos = (pos_y + verticalCellHeight / 2) - (oneLineTextHeight / 2); - - verticalAlignPos_text = (pos_y + verticalCellHeight / 2) ; - luckysheetTableContent.textBaseline = "middle"; - } - else if(verticalAlign == "1"){ //上对齐 - verticalAlignPos = (pos_y + space_height) ; - - verticalAlignPos_text = (pos_y + space_height) ; - luckysheetTableContent.textBaseline = "top"; - } - - verticalAlignPos = verticalAlignPos/Store.zoomRatio; - horizonAlignPos = horizonAlignPos/Store.zoomRatio; - verticalAlignPos_text = verticalAlignPos_text/Store.zoomRatio; - - //交替颜色 - let checksAF = alternateformat.checksAF(r, c, af_compute); - //条件格式 - let checksCF = conditionformat.checksCF(r, c, cf_compute); - - //单元格 文本颜色 - luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , "fc"); - - //若单元格有交替颜色 文本颜色 - if(checksAF != null && checksAF[0] != null){ - luckysheetTableContent.fillStyle = checksAF[0]; - } - //若单元格有条件格式 文本颜色 - if(checksCF != null && checksCF["textColor"] != null){ - luckysheetTableContent.fillStyle = checksCF["textColor"]; - } - - luckysheetTableContent.fillText(value == null ? "" : value, horizonAlignPos, verticalAlignPos_text); - - luckysheetTableContent.restore(); - - //单元格是否有删除线 - let cl = menuButton.checkstatus(Store.flowdata, r, c , "cl"); - if(cl == "1" && !isRealNull(value)){ - luckysheetTableContent.beginPath(); - luckysheetTableContent.strokeStyle = "#000"; - luckysheetTableContent.moveTo( - horizonAlignPos, - verticalAlignPos + oneLineTextHeight / 2/Store.zoomRatio - ); - luckysheetTableContent.lineTo( - horizonAlignPos + textMetrics/Store.zoomRatio, - verticalAlignPos + oneLineTextHeight / 2/Store.zoomRatio - ); - luckysheetTableContent.stroke(); - luckysheetTableContent.closePath(); - } -} - -//获取表格渲染范围 溢出单元格 -function getCellOverflowMap(canvas, col_st, col_ed, row_st, row_end){ - let map = {}; - - let data = Store.flowdata; - - for(let r = row_st; r <= row_end; r++){ - for(let c = 0; c < data[r].length; c++){ - let cell = data[r][c]; - - if (Store.config["colhidden"] != null && Store.config["colhidden"][c] != null) { - continue - } - - if(cell != null && !isRealNull(cell.v) && cell.mc == null && cell.tb == '1'){ - let fontset = luckysheetfontformat(cell); - canvas.font = fontset; - - //水平对齐 - let horizonAlign = menuButton.checkstatus(data, r, c, "ht"); - - //文本宽度 - let value = getcellvalue(r, c, null, "m"); - if(value == null){ - value = getcellvalue(r, c); - } - let textMetrics = getMeasureText(value, canvas).width; + let textMetrics = getCellTextInfo(cell, canvas,{ + r:r, + c:c, + }).textWidthAll; //canvas.measureText(value).width; let start_c = c - 1 < 0 ? 0 : Store.visibledatacolumn[c - 1]; @@ -2839,7 +2013,7 @@ function cellTextRender(textInfo, ctx, option){ if(values==null){ return; } - console.log(textInfo, pos_x, pos_y, values[0].width, values[0].left, values[0].style); + console.log(textInfo, pos_x, pos_y, values[0].width, values[0].left, ctx); if(textInfo.rotate!=0 && textInfo.type!="verticalWrap"){ ctx.save(); diff --git a/src/global/getRowlen.js b/src/global/getRowlen.js index 66197e1..fb26a0c 100644 --- a/src/global/getRowlen.js +++ b/src/global/getRowlen.js @@ -35,57 +35,65 @@ function rowlenByRange(d, r1, r2, cfg) { } if(cell != null && cell.v != null){ - let fontset = luckysheetfontformat(cell); - canvas.font = fontset; - - let value = getcellvalue(r, c, d).toString(); //单元格文本 - let measureText = getMeasureText(value, canvas); - - let textMetrics = measureText.width; //文本宽度 - let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent; - let spaceHeight = Math.ceil(oneLineTextHeight/3); - let computeRowlen; //计算行高 - let word_space_height = oneLineTextHeight/3; - if(cell.tb == "2"){ - //自动换行 - let cellWidth = colLocationByIndex(c)[1] - colLocationByIndex(c)[0] - 4; //单元格宽度 - - if(textMetrics > cellWidth){ - let strArr = []; //文本截断数组 - strArr = getCellTextSplitArr(value, strArr, cellWidth, canvas); - - computeRowlen = (oneLineTextHeight+word_space_height) * strArr.length + spaceHeight; - } - else{ - computeRowlen = oneLineTextHeight + spaceHeight; - } - } - else if(cell.tr != null){ - //单元格有旋转标示 - let tr = cell.tr; - - if(tr == "0"){ - //无旋转 - computeRowlen = oneLineTextHeight + spaceHeight; - } - else if(tr == "1" || tr == "2"){ - //向下倾斜(45 旋转)----向上倾斜(-45 旋转) - computeRowlen = 0.707 * (textMetrics + oneLineTextHeight) + spaceHeight; - } - else if(tr == "3"){ - //竖排文字 - computeRowlen = value.length * oneLineTextHeight + spaceHeight; - } - else if(tr == "4" || tr == "5"){ - //向下90(90 旋转)----向上90(-90 旋转) - computeRowlen = textMetrics + spaceHeight; - } - computeRowlen = Math.round(computeRowlen); - } - else{ - computeRowlen = oneLineTextHeight + spaceHeight; - } + let textInfo = getCellTextInfo(cell, canvas,{ + r:r, + c:c, + }); + + let computeRowlen = textInfo.textHeightAll; + + // let fontset = luckysheetfontformat(cell); + // canvas.font = fontset; + + // let value = getcellvalue(r, c, d).toString(); //单元格文本 + // let measureText = getMeasureText(value, canvas); + + // let textMetrics = measureText.width; //文本宽度 + // let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent; + // let spaceHeight = Math.ceil(oneLineTextHeight/3); + // let computeRowlen; //计算行高 + // let word_space_height = oneLineTextHeight/3; + // if(cell.tb == "2"){ + // //自动换行 + // let cellWidth = colLocationByIndex(c)[1] - colLocationByIndex(c)[0] - 4; //单元格宽度 + + // if(textMetrics > cellWidth){ + // let strArr = []; //文本截断数组 + // strArr = getCellTextSplitArr(value, strArr, cellWidth, canvas); + + // computeRowlen = (oneLineTextHeight+word_space_height) * strArr.length + spaceHeight; + // } + // else{ + // computeRowlen = oneLineTextHeight + spaceHeight; + // } + // } + // else if(cell.tr != null){ + // //单元格有旋转标示 + // let tr = cell.tr; + + // if(tr == "0"){ + // //无旋转 + // computeRowlen = oneLineTextHeight + spaceHeight; + // } + // else if(tr == "1" || tr == "2"){ + // //向下倾斜(45 旋转)----向上倾斜(-45 旋转) + // computeRowlen = 0.707 * (textMetrics + oneLineTextHeight) + spaceHeight; + // } + // else if(tr == "3"){ + // //竖排文字 + // computeRowlen = value.length * oneLineTextHeight + spaceHeight; + // } + // else if(tr == "4" || tr == "5"){ + // //向下90(90 旋转)----向上90(-90 旋转) + // computeRowlen = textMetrics + spaceHeight; + // } + + // computeRowlen = Math.round(computeRowlen); + // } + // else{ + // computeRowlen = oneLineTextHeight + spaceHeight; + // } //比较计算高度和当前高度取最大高度 if(computeRowlen > currentRowLen){ @@ -95,7 +103,7 @@ function rowlenByRange(d, r1, r2, cfg) { } currentRowLen = currentRowLen/Store.zoomRatio; - + console.log(currentRowLen); if(currentRowLen != Store.defaultrowlen){ cfg_clone["rowlen"][r] = currentRowLen; } @@ -179,8 +187,18 @@ function getMeasureText(value, ctx, fontset){ commonWord = "田"; } let oneLineTextHeight = menuButton.getTextSize(commonWord, ctx.font)[1]*0.8; - cache.actualBoundingBoxDescent = oneLineTextHeight/2; - cache.actualBoundingBoxAscent = oneLineTextHeight/2; + if(ctx.textBaseline=="top"){ + cache.actualBoundingBoxDescent = oneLineTextHeight; + cache.actualBoundingBoxAscent = 0; + } + else if(ctx.textBaseline=="middle"){ + cache.actualBoundingBoxDescent = oneLineTextHeight/2; + cache.actualBoundingBoxAscent = oneLineTextHeight/2; + } + else{ + cache.actualBoundingBoxDescent = 0; + cache.actualBoundingBoxAscent = oneLineTextHeight; + } //console.log(value, oneLineTextHeight, measureText.actualBoundingBoxDescent+measureText.actualBoundingBoxAscent,ctx.font); } @@ -206,11 +224,29 @@ function isSupportBoundingBox(ctx){ // let measureTextCache = {}, measureTextCacheTimeOut = null; // option {cellWidth,cellHeight,space_width,space_height} function getCellTextInfo(cell , ctx, option){ - // let cell = Store.flowdata[r][c]; let cellWidth = option.cellWidth; let cellHeight = option.cellHeight; + let isMode = "", isModeSplit = ""; + if(cellWidth==null){ + isMode = "onlyWidth"; + isModeSplit = "_"; + } + let textInfo = Store.measureTextCellInfoCache[option.r + "_" + option.c + isModeSplit + isMode]; + if(textInfo != null){ + return textInfo; + } + + // let cell = Store.flowdata[r][c]; let space_width = option.space_width, space_height = option.space_height; //宽高方向 间隙 + if(space_width==null){ + space_width = 2; + } + + if(space_height==null){ + space_height = 2; + } + //水平对齐 let horizonAlign = menuButton.checkstatusByCell(cell, "ht"); //垂直对齐 @@ -352,6 +388,14 @@ function getCellTextInfo(cell , ctx, option){ textW_all += colMaxW; textH_all = Math.max(textH_all, columnHeight); } + + textContent.type = "verticalWrap"; + textContent.textWidthAll = textW_all; + textContent.textHeightAll = textH_all; + + if(isMode=="onlyWidth"){ + return textContent; + } let cumColumnWidth = 0; for(let i = 0; i < textH_all_ColumnHeight.length; i++){ @@ -390,10 +434,6 @@ function getCellTextInfo(cell , ctx, option){ cumColumnWidth+=columnWidth; } - - textContent.type = "verticalWrap"; - textContent.textWidthAll = textW_all; - textContent.textHeightAll = textH_all; } else{ let supportBoundBox = isSupportBoundingBox(ctx); @@ -416,8 +456,8 @@ function getCellTextInfo(cell , ctx, option){ textContent.rotate = rt; rt = Math.abs(rt); - let anchor = 0, preHeight = 0, preWidth=0, preStr, preTextHeight, preTextWidth; - for(let i = 1; i <= value.length; i++){ + let anchor = 0, preHeight = 0, preWidth=0, preStr, preTextHeight, preTextWidth, i=0; + while(i <= value.length){ let str = value.substring(anchor, i); let measureText = getMeasureText(str, ctx); let textWidth = measureText.width; @@ -429,12 +469,10 @@ function getCellTextInfo(cell , ctx, option){ // textW_all += textW; - if(text_all_split[splitIndex]==null){ - text_all_split[splitIndex]= []; - } - if(rt!=0){//rotate - if((height+space_height)>cellHeight){ + console.log("all",anchor, i , str); + if((height+space_height)>cellHeight && text_all_split[splitIndex]!=null){ + console.log("cut",anchor, i , str); anchor = i-1; text_all_split[splitIndex].push({ @@ -454,7 +492,10 @@ function getCellTextInfo(cell , ctx, option){ splitIndex +=1; } else if(i== value.length){ - + console.log("last",anchor, i , str); + if(text_all_split[splitIndex]==null){ + text_all_split[splitIndex]= []; + } text_all_split[splitIndex].push({ content:str, style:fontset, @@ -468,10 +509,17 @@ function getCellTextInfo(cell , ctx, option){ asc:measureText.actualBoundingBoxAscent, desc:measureText.actualBoundingBoxDescent }); + break; + } + else{ + if(text_all_split[splitIndex]==null){ + text_all_split[splitIndex]= []; + } + i++; } } else{//plain - if((width+space_width)>cellWidth){ + if((width+space_width)>cellWidth && text_all_split[splitIndex]!=null){ anchor = i-1; @@ -490,7 +538,9 @@ function getCellTextInfo(cell , ctx, option){ splitIndex +=1; } else if(i== value.length){ - + if(text_all_split[splitIndex]==null){ + text_all_split[splitIndex]= []; + } text_all_split[splitIndex].push({ content:str, style:fontset, @@ -502,6 +552,14 @@ function getCellTextInfo(cell , ctx, option){ asc:measureText.actualBoundingBoxAscent, desc:measureText.actualBoundingBoxDescent }); + + break; + } + else{ + if(text_all_split[splitIndex]==null){ + text_all_split[splitIndex]= []; + } + i++; } } @@ -514,20 +572,19 @@ function getCellTextInfo(cell , ctx, option){ } let split_all_size = []; - console.log(splitIndex, text_all_split); + // console.log(splitIndex, text_all_split); let splitLen = Object.keys(text_all_split).length; for(let i = 0; i < splitLen; i++){ let splitLists = text_all_split[i]; if(splitLists==null){ continue; } - let sWidth = 0, sHeight=0, textHeight=0; + let sWidth = 0, sHeight=0; for(let s=0;s Date: Mon, 14 Sep 2020 09:52:45 +0800 Subject: [PATCH 10/19] fix(render bug fix): new render method --- src/controllers/menuButton.js | 4 +- src/global/draw.js | 48 ++++- src/global/getRowlen.js | 368 ++++++++++++++++++++++++++-------- src/index.html | 40 +--- 4 files changed, 328 insertions(+), 132 deletions(-) diff --git a/src/controllers/menuButton.js b/src/controllers/menuButton.js index 7b9e046..e06ab20 100644 --- a/src/controllers/menuButton.js +++ b/src/controllers/menuButton.js @@ -2948,10 +2948,10 @@ const menuButton = { } if(attr == "tb" || attr == "tr" || attr == "fs"){ - jfrefreshgrid(d, Store.luckysheet_select_save, cfg, null, true); + jfrefreshgrid(d, Store.luckysheet_select_save, cfg, null, true, false); } else{ - jfrefreshgrid(d, Store.luckysheet_select_save); + jfrefreshgrid(d, Store.luckysheet_select_save, undefined, undefined,undefined,false); } }, updateFormat_mc: function(d, foucsStatus){ diff --git a/src/global/draw.js b/src/global/draw.js index d717dd6..c9507dc 100644 --- a/src/global/draw.js +++ b/src/global/draw.js @@ -1517,7 +1517,17 @@ let cellRender = function(r, c, start_r, start_c, end_r, end_c, value, luckyshee let value = textInfo.values[0] let horizonAlignPos = pos_x + value.left; - let verticalAlignPos = pos_y + value.top; + let verticalAlignPos = pos_y + value.top- textInfo.textHeightAll; + + if(verticalAlign == "0"){ //居中对齐 + verticalAlignPos = pos_y + cellHeight/2 - textInfo.textHeightAll/2; + } + else if(verticalAlign == "1"){ //上对齐 + verticalAlignPos = pos_y; + } + else if(verticalAlign == "2"){ //下对齐 + verticalAlignPos =verticalAlignPos - textInfo.desc; + } verticalAlignPos = verticalAlignPos/Store.zoomRatio; horizonAlignPos = horizonAlignPos/Store.zoomRatio; @@ -1530,12 +1540,12 @@ let cellRender = function(r, c, start_r, start_c, end_r, end_c, value, luckyshee 32, pos_x/Store.zoomRatio , verticalAlignPos, - textContent.textHeightAll/Store.zoomRatio, - textContent.textHeightAll/Store.zoomRatio + textInfo.textHeightAll/Store.zoomRatio, + textInfo.textHeightAll/Store.zoomRatio ); if(horizonAlign != "0" && horizonAlign != "2"){ //左对齐时 文本渲染空出一个图标的距离 - horizonAlignPos = horizonAlignPos + textContent.textHeightAll/Store.zoomRatio; + horizonAlignPos = horizonAlignPos + textInfo.textHeightAll/Store.zoomRatio; } } @@ -1805,10 +1815,15 @@ function getCellOverflowMap(canvas, col_st, col_ed, row_st, row_end){ // value = getcellvalue(r, c); // } - let textMetrics = getCellTextInfo(cell, canvas,{ + let textMetricsObj = getCellTextInfo(cell, canvas,{ r:r, c:c, - }).textWidthAll; + }); + let textMetrics = 0; + if(textMetricsObj!=null){ + textMetrics = textMetricsObj.textWidthAll; + } + //canvas.measureText(value).width; let start_c = c - 1 < 0 ? 0 : Store.visibledatacolumn[c - 1]; @@ -2008,12 +2023,24 @@ function cellOverflow_colIn(map, r, c, col_st, col_ed){ } function cellTextRender(textInfo, ctx, option){ + if(textInfo==null){ + return + } let values = textInfo.values; let pos_x = option.pos_x, pos_y = option.pos_y; if(values==null){ return; } - console.log(textInfo, pos_x, pos_y, values[0].width, values[0].left, ctx); + // console.log(textInfo, pos_x, pos_y, values[0].width, values[0].left, ctx); + + // for(let i=0;icellHeight && text_all_split[splitIndex]!=null){ - console.log("cut",anchor, i , str); + // console.log("cut",anchor, i , str); anchor = i-1; text_all_split[splitIndex].push({ @@ -492,7 +507,7 @@ function getCellTextInfo(cell , ctx, option){ splitIndex +=1; } else if(i== value.length){ - console.log("last",anchor, i , str); + // console.log("last",anchor, i , str); if(text_all_split[splitIndex]==null){ text_all_split[splitIndex]= []; } @@ -571,15 +586,15 @@ function getCellTextInfo(cell , ctx, option){ } - let split_all_size = []; - // console.log(splitIndex, text_all_split); + let split_all_size = [], oneLinemaxWordCount=0; + // console.log("split",splitIndex, text_all_split); let splitLen = Object.keys(text_all_split).length; for(let i = 0; i < splitLen; i++){ let splitLists = text_all_split[i]; if(splitLists==null){ continue; } - let sWidth = 0, sHeight=0; + let sWidth = 0, sHeight=0, maxDesc=0,maxAsc=0, lineHeight=0, maxWordCount=0; for(let s=0;s1?(wordGroup.textHeight/1.5):0); + // if(verticalAlign == "0"){ + // top = y + cellHeight/2 - topOffset - textH_all/2 + wordGroup.asc+(splitLen>1?(wordGroup.textHeight/3):0); + // } + // else if(verticalAlign == "1"){ + // top = y - topOffset + wordGroup.asc; + // } - cumColumnWidth += wordGroup.textWidth; - - if(c==0 && i==0 && isRotateUp=="1"){ - textContent.textLeftAll = left; - textContent.textTopAll = top-wordGroup.asc; - } - else if(c==0 && i==(splitLen-1) && isRotateUp=="0"){ - textContent.textLeftAll = left; - textContent.textTopAll = top+wordGroup.desc; - } - - console.log("plainWrap" ,left , top); + // cumColumnWidth += wordGroup.textWidth; + + // if(c==0 && i==0 && isRotateUp=="1"){ + // textContent.textLeftAll = left; + // textContent.textTopAll = top-wordGroup.asc; + // } + // else if(c==0 && i==(splitLen-1) && isRotateUp=="0"){ + // textContent.textLeftAll = left; + // textContent.textTopAll = top+wordGroup.desc; + // } + + // console.log("plainWrap" ,left , top); } else{//plain left = space_width + cumColumnWidth; @@ -706,9 +869,9 @@ function getCellTextInfo(cell , ctx, option){ left = cellWidth + cumColumnWidth - size.width; } - top = (cellHeight - space_height) + cumWordHeight - textH_all - wordGroup.desc + wordGroup.height*2/1.5-1; + top = (cellHeight - space_height) + cumWordHeight - textH_all + wordGroup.asc+wordGroup.height/1.5-wordGroup.desc-1; if(verticalAlign == "0"){ - top = cellHeight / 2 + cumWordHeight - textH_all/2 + wordGroup.height/2 + wordGroup.height/3+1; + top = cellHeight / 2 + cumWordHeight - textH_all/2 + wordGroup.asc+wordGroup.height/3-wordGroup.desc; } else if(verticalAlign == "1"){ top = space_height + cumWordHeight+ wordGroup.asc; @@ -733,22 +896,59 @@ function getCellTextInfo(cell , ctx, option){ textContent.type = "plainWrap"; if(rt!=0){ - // textContent.textWidthAll = rw; - // textContent.textHeightAll = rh; - - let leftCenter = (textW_all + textH_all/Math.tan(rt*Math.PI/180))/2; - let topCenter = textH_all/2; - - // let leftCenter = 0; - // let topCenter = 0; - - if(isRotateUp=="1"){ - textContent.textLeftAll += leftCenter; - textContent.textTopAll += topCenter; + // let leftCenter = (textW_all + textH_all/Math.tan(rt*Math.PI/180))/2; + // let topCenter = textH_all/2; + + // if(isRotateUp=="1"){ + // textContent.textLeftAll += leftCenter; + // textContent.textTopAll += topCenter; + // } + // else { + // textContent.textLeftAll += leftCenter; + // textContent.textTopAll -= topCenter; + // } + + if(horizonAlign == "0"){//center + if(verticalAlign == "0"){//mid + textContent.textLeftAll = cellWidth/2; + textContent.textTopAll = cellHeight/2; + } + else if(verticalAlign == "1"){//top + textContent.textLeftAll = cellWidth/2; + textContent.textTopAll = rh/2; + } + else if(verticalAlign == "2"){//bottom + textContent.textLeftAll = cellWidth/2; + textContent.textTopAll = cellHeight - rh/2; + } } - else { - textContent.textLeftAll += leftCenter; - textContent.textTopAll -= topCenter; + else if(horizonAlign == "1"){//left + if(verticalAlign == "0"){//mid + textContent.textLeftAll = 0; + textContent.textTopAll = cellHeight/2; + } + else if(verticalAlign == "1"){//top + textContent.textLeftAll = 0; + textContent.textTopAll = 0; + } + else if(verticalAlign == "2"){//bottom + textContent.textLeftAll = 0; + textContent.textTopAll = cellHeight; + } + } + else if(horizonAlign == "2"){//right + if(verticalAlign == "0"){//mid + textContent.textLeftAll = cellWidth - rw/2; + textContent.textTopAll = cellHeight/2; + } + else if(verticalAlign == "1"){//top + textContent.textLeftAll = cellWidth; + textContent.textTopAll = 0; + } + else if(verticalAlign == "2"){//bottom + textContent.textLeftAll = cellWidth; + textContent.textTopAll = cellHeight; + } } } @@ -786,8 +986,9 @@ function getCellTextInfo(cell , ctx, option){ } textContent.textWidthAll = textWidthAll; - console.log(textContent.textWidthAll , textContent.textHeightAll); + // console.log(textContent.textWidthAll , textContent.textHeightAll); if(isMode=="onlyWidth"){ + // console.log("plain", textContent,cell, option); return textContent; } @@ -822,7 +1023,10 @@ function getCellTextInfo(cell , ctx, option){ textContent.textLeftAll = left; textContent.textTopAll = top; - console.log("plain",left,top); + textContent.asc = measureText.actualBoundingBoxAscent; + textContent.desc = measureText.actualBoundingBoxDescent; + + // console.log("plain",left,top); } } diff --git a/src/index.html b/src/index.html index bd30e77..a724e83 100644 --- a/src/index.html +++ b/src/index.html @@ -37,45 +37,7 @@ allowEdit:true, forceCalculation:false, plugins: ['chart'], - data: [{"name":"Sheet1","config":{"columnlen":{"0":241},"rowlen":{"0":81}},"index":"1","status":"1","order":"0","luckysheet_select_save":[{"row":[0,0],"column":[4,4],"sheetIndex":1}],"zoomRatio":1,"showGridLines":"1","defaultColWidth":72,"defaultRowHeight":18,"celldata":[ - {"r":0,"c":0, - "v":{ - "ct":{ - "fa":"General", - "t":"inlineStr", - "sharedStrings":[ - { - "ff":"等线", //font family - "fc":"#fff000",//font color - "fs":12,//font size - "cl":1,//strike - "un":0,//underline - "bl":0,//blod - "it":1,//italic - v:"我在\r\n" - }, - { - "ff":"等线", //font family - "fc":"#ff0000",//font color - "fs":14,//font size - "cl":"1",//strike - "un":"0",//underline - "bl":"1",//blod - "it":"0",//italic - v:"马路边" - }, - ] - }, - "fs":11, - "ff":"等线", - "vt":0, - "tb":2, - "v":"", - "qp":1, - } - }, - {"r":17,"c":2,"v":{"v":"Luckysheet","ct":{"fa":"General","t":"g"},"bg":null,"bl":0,"it":0,"ff":0,"fs":"11","fc":"rgb(51, 51, 51)","ht":1,"vt":1,"m":"Luckysheet"}} - ],"calcChain":[]}] + data: [sheetCell,sheetFormula,sheetConditionFormat,sheetSparkline,sheetTable,sheetComment,sheetPivotTableData,sheetPivotTable,sheetChart] }) }) From 592c1638c7449e350bc6c8d3fa8969fe38b9887f Mon Sep 17 00:00:00 2001 From: wbfsa Date: Mon, 14 Sep 2020 11:34:49 +0800 Subject: [PATCH 11/19] style(inline string): programing --- src/global/getRowlen.js | 417 ++++++++++++++++++++++++---------------- src/index.html | 44 ++++- 2 files changed, 298 insertions(+), 163 deletions(-) diff --git a/src/global/getRowlen.js b/src/global/getRowlen.js index b0ac776..a39996a 100644 --- a/src/global/getRowlen.js +++ b/src/global/getRowlen.js @@ -294,6 +294,8 @@ function getCellTextInfo(cell , ctx, option){ isRotateDown = 1; } + ctx.textAlign="start"; + let textContent = {}; textContent.values = []; @@ -667,84 +669,176 @@ function getCellTextInfo(cell , ctx, option){ return textContent; } - - - for(let i = 0; i < splitLen; i++){ - let splitLists = text_all_split[i]; - if(splitLists==null){ - continue; - } - let size = split_all_size[i]; - - cumColumnWidth = 0; - - for(let c=0;c=0;c--){ + let wordGroup = splitLists[c]; + let left, top; + if(rt!=0){//rotate + let x, y = cumWordHeight+size.asc; + if(isRotateUp=="1"){ + // x = (cumWordHeight)/Math.tan(rtPI) + cumColumnWidth; + // if(verticalAlign=="2"){ + // x = (cumWordHeight)/Math.tan(rtPI) - cumColumnWidth + textW_all_inner; + // } + // else if(verticalAlign=="0"){ + // x = (cumWordHeight)/Math.tan(rtPI) - cumColumnWidth + textW_all_inner; + // } + // else{ + // x = (cumWordHeight)/Math.tan(rtPI) - cumColumnWidth + textW_all_inner; + // } + + if(horizonAlign == "0"){//center + let sh = textH_all/Math.sin(rtPI); + x = (cumWordHeight)/Math.tan(rt*Math.PI/180) - cumColumnWidth + textW_all_inner; + if(verticalAlign == "0"){//mid + + left = x + cellWidth/2 - (textW_all/2); + top = y + cellHeight/2 - textH_all/2; + } + else if(verticalAlign == "1"){//top + left = x + cellWidth/2 - textW_all/2- lastLineSpaceHeight*Math.cos(rtPI)/2; + top = y - (textH_all/2 - rh/2) + lastLineSpaceHeight*Math.sin(rtPI)/2; + } + else if(verticalAlign == "2"){//bottom + left = x + cellWidth/2 - (textW_all/2); + top = y + cellHeight - rh/2-textH_all/2; + } } - else if(verticalAlign == "1"){//top fixOneLineLeft - left = x + cellWidth - textW_all + lastLine.height*Math.cos(rtPI)/2; - top = y - textH_all + lastLine.height*Math.sin(rtPI)/2; + else if(horizonAlign == "1"){//left + x = (cumWordHeight)/Math.tan(rtPI) - cumColumnWidth + textW_all_inner; + if(verticalAlign == "0"){//mid + left = x - rh*Math.sin(rtPI)/2 + lastLineSpaceHeight*Math.cos(rtPI)/2; + top = y + cellHeight/2 + rh*Math.cos(rtPI)/2 - lastLineSpaceHeight*Math.sin(rtPI)/2; + } + else if(verticalAlign == "1"){//top + left = x - rh*Math.sin(rtPI); + top = y + rh*Math.cos(rtPI); + } + else if(verticalAlign == "2"){//bottom + left = x + lastLineSpaceHeight*Math.cos(rtPI); + top = y + cellHeight - lastLineSpaceHeight*Math.sin(rtPI); + } } - else if(verticalAlign == "2"){//bottom - left = x + cellWidth - rw*Math.cos(rtPI) + lastLineSpaceHeight*Math.cos(rtPI); - top = y + cellHeight - rw*Math.sin(rtPI) + lastLineSpaceHeight*Math.sin(rtPI); + else if(horizonAlign == "2"){//right + x = (cumWordHeight)/Math.tan(rtPI) - cumColumnWidth + textW_all_inner; + if(verticalAlign == "0"){//mid + // left = x + cellWidth - ( textH_all/Math.tan(rtPI) + (rh/2)*Math.sin(rtPI)); + // top = y + cellHeight/2 - (textH_all - (rh/2)*Math.cos(rtPI)); + left = x + cellWidth - rw/2 - (textW_all_inner/2+(textH_all/2)/Math.tan(rtPI)); + top = y + cellHeight/2 - textH_all/2; + } + else if(verticalAlign == "1"){//top fixOneLineLeft + left = x + cellWidth - textW_all + lastLine.height*Math.cos(rtPI)/2; + top = y - textH_all + lastLine.height*Math.sin(rtPI)/2; + } + else if(verticalAlign == "2"){//bottom + left = x + cellWidth - rw*Math.cos(rtPI) + lastLineSpaceHeight*Math.cos(rtPI); + top = y + cellHeight - rw*Math.sin(rtPI) - lastLineSpaceHeight*Math.sin(rtPI); + } } } + } - else{ + + wordGroup.left = left; + wordGroup.top = top; + + textContent.values.push(wordGroup); + } + + + cumWordHeight += size.height; + + + } + } + else{ + for(let i = 0; i < splitLen; i++){ + let splitLists = text_all_split[i]; + if(splitLists==null){ + continue; + } + let size = split_all_size[i]; + + cumColumnWidth = 0; + + for(let c=0;c1?(wordGroup.textHeight/1.5):0); - // if(verticalAlign == "0"){ - // top = y + cellHeight/2 - topOffset - textH_all/2 + wordGroup.asc+(splitLen>1?(wordGroup.textHeight/3):0); - // } - // else if(verticalAlign == "1"){ - // top = y - topOffset + wordGroup.asc; - // } + // let x, y = cumWordHeight; //+ wordGroup.textHeight / Math.sin(rt*Math.PI/180)*isRotateDown; + // if(isRotateUp=="1"){ + // if(horizonAlign=="2"){ + // x = (cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // else if(horizonAlign=="0"){ + // x = (cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // else{ + // x = (cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // } + // else{ + // if(horizonAlign=="2"){ + // x = (textH_all-cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // else if(horizonAlign=="0"){ + // x = (textH_all-cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // else{ + // x = (textH_all-cumWordHeight)/Math.tan(rt*Math.PI/180) + cumColumnWidth; + // } + // } - // cumColumnWidth += wordGroup.textWidth; - - // if(c==0 && i==0 && isRotateUp=="1"){ - // textContent.textLeftAll = left; - // textContent.textTopAll = top-wordGroup.asc; - // } - // else if(c==0 && i==(splitLen-1) && isRotateUp=="0"){ - // textContent.textLeftAll = left; - // textContent.textTopAll = top+wordGroup.desc; - // } - - // console.log("plainWrap" ,left , top); - } - else{//plain - left = space_width + cumColumnWidth; - if(horizonAlign == "0"){ - //+ space_width*textH_all_ColumnHeight.length - left = cellWidth / 2 + cumColumnWidth - size.width/2; - } - else if(horizonAlign == "2"){ - left = cellWidth + cumColumnWidth - size.width; - } + // // x -= wordGroup.textHeight / Math.sin(rt*Math.PI/180)*isRotateDown; + // // x -= size.textHeight*2; + // //textH_all/Math.sin(rt*Math.PI/180) - textH_all/Math.tan(rt*Math.PI/180); + // let leftOffset = 0; + + // left = x + leftOffset; + // if(horizonAlign == "0"){ + // //+ space_width*textH_all_ColumnHeight.length + // left = x + cellWidth / 2 + leftOffset - textW_all/2; + // } + // else if(horizonAlign == "2"){ + // left = x + cellWidth + leftOffset - textW_all; + // } - top = (cellHeight - space_height) + cumWordHeight - textH_all + wordGroup.asc+wordGroup.height/1.5-wordGroup.desc-1; - if(verticalAlign == "0"){ - top = cellHeight / 2 + cumWordHeight - textH_all/2 + wordGroup.asc+wordGroup.height/3-wordGroup.desc; + // //( textH_all/2 - rh/2 ) + // let topOffset = 0; + + // top = y + cellHeight - topOffset - textH_all + wordGroup.asc +wordGroup.desc +(splitLen>1?(wordGroup.textHeight/1.5):0); + // if(verticalAlign == "0"){ + // top = y + cellHeight/2 - topOffset - textH_all/2 + wordGroup.asc+(splitLen>1?(wordGroup.textHeight/3):0); + // } + // else if(verticalAlign == "1"){ + // top = y - topOffset + wordGroup.asc; + // } + + // cumColumnWidth += wordGroup.textWidth; + + // if(c==0 && i==0 && isRotateUp=="1"){ + // textContent.textLeftAll = left; + // textContent.textTopAll = top-wordGroup.asc; + // } + // else if(c==0 && i==(splitLen-1) && isRotateUp=="0"){ + // textContent.textLeftAll = left; + // textContent.textTopAll = top+wordGroup.desc; + // } + + // console.log("plainWrap" ,left , top); } - else if(verticalAlign == "1"){ - top = space_height + cumWordHeight+ wordGroup.asc; + else{//plain + left = space_width + cumColumnWidth; + if(horizonAlign == "0"){ + //+ space_width*textH_all_ColumnHeight.length + left = cellWidth / 2 + cumColumnWidth - size.width/2; + } + else if(horizonAlign == "2"){ + left = cellWidth + cumColumnWidth - size.width; + } + + top = (cellHeight - space_height) + cumWordHeight - textH_all + wordGroup.asc+wordGroup.height/1.5-wordGroup.desc-1; + if(verticalAlign == "0"){ + top = cellHeight / 2 + cumWordHeight - textH_all/2 + wordGroup.asc+wordGroup.height/3-wordGroup.desc; + } + else if(verticalAlign == "1"){ + top = space_height + cumWordHeight+ wordGroup.asc; + } + + cumColumnWidth += wordGroup.width; } + + + wordGroup.left = left; + wordGroup.top = top; - cumColumnWidth += wordGroup.width; + textContent.values.push(wordGroup); } - - - wordGroup.left = left; - wordGroup.top = top; - - textContent.values.push(wordGroup); + + + cumWordHeight += size.height; + + } - - - cumWordHeight += size.height; - - } textContent.type = "plainWrap"; diff --git a/src/index.html b/src/index.html index a724e83..5534a29 100644 --- a/src/index.html +++ b/src/index.html @@ -30,14 +30,54 @@ import sheetSparkline from './demoData/sheetSparkline.js' import sheetChart from './demoData/sheetChart.js' $(function () { - + // [sheetCell,sheetFormula,sheetConditionFormat,sheetSparkline,sheetTable,sheetComment,sheetPivotTableData,sheetPivotTable,sheetChart] + // [{"name":"Sheet1","config":{"columnlen":{"0":241},"rowlen":{"0":81}},"index":"1","status":"1","order":"0","luckysheet_select_save":[{"row":[0,0],"column":[4,4],"sheetIndex":1}],"zoomRatio":1,"showGridLines":"1","defaultColWidth":72,"defaultRowHeight":18,"celldata":[ + // {"r":0,"c":0, + // "v":{ + // "ct":{ + // "fa":"General", + // "t":"inlineStr", + // "sharedStrings":[ + // { + // "ff":"等线", //font family + // "fc":"#fff000",//font color + // "fs":12,//font size + // "cl":1,//strike + // "un":0,//underline + // "bl":0,//blod + // "it":1,//italic + // v:"我在\r\n" + // }, + // { + // "ff":"等线", //font family + // "fc":"#ff0000",//font color + // "fs":14,//font size + // "cl":"1",//strike + // "un":"0",//underline + // "bl":"1",//blod + // "it":"0",//italic + // v:"马路边" + // }, + // ] + // }, + // "fs":11, + // "ff":"等线", + // "vt":0, + // "tb":2, + // "v":"", + // "qp":1, + // } + // }, + // {"r":17,"c":2,"v":{"v":"Luckysheet","ct":{"fa":"General","t":"g"},"bg":null,"bl":0,"it":0,"ff":0,"fs":"11","fc":"rgb(51, 51, 51)","ht":1,"vt":1,"m":"Luckysheet"}} + // ],"calcChain":[]}] + luckysheet.create({ container: 'luckysheet', lang: 'en', allowEdit:true, forceCalculation:false, plugins: ['chart'], - data: [sheetCell,sheetFormula,sheetConditionFormat,sheetSparkline,sheetTable,sheetComment,sheetPivotTableData,sheetPivotTable,sheetChart] + data: [sheetCell,sheetFormula,sheetConditionFormat,sheetSparkline,sheetTable,sheetComment,sheetPivotTableData,sheetPivotTable,sheetChart] }) }) From bf831386566d4253d27b746424950844afcc6405 Mon Sep 17 00:00:00 2001 From: lrz <1414556676@qq.com> Date: Mon, 14 Sep 2020 17:44:03 +0800 Subject: [PATCH 12/19] docs(readme): readme cdn --- README-zh.md | 18 ++++++++---------- README.md | 19 ++++++++----------- docs/guide/README.md | 24 +++++++++++++++++++----- docs/zh/guide/README.md | 25 ++++++++++++++++++++----- docs/zh/guide/cell.md | 11 +++++++++-- src/global/api.js | 1 + 6 files changed, 65 insertions(+), 33 deletions(-) diff --git a/README-zh.md b/README-zh.md index e3de471..4803cc8 100644 --- a/README-zh.md +++ b/README-zh.md @@ -124,23 +124,21 @@ npm run build ## 用法 #### 第一步 -`npm run build`后`dist`文件夹下的所有文件复制到项目目录 +通过CDN引入依赖 -#### 第二步 -引入依赖 ``` - - - - - + + + + + ``` -#### 第三步 +#### 第二步 指定一个表格容器 ```
``` -#### 第四步 +#### 第三步 创建一个表格 ``` - + + + + + ``` -#### Third step +#### Second step Specify a table container ```
``` -#### Fourth step +#### Third step Create a table ``` + +``` + +Note that `https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js` will pull the latest luckysheet code. If you want to specify the luckysheet version, please add the version number after the luckysheet , Such as: `https://cdn.jsdelivr.net/npm/luckysheet@2.0.0/dist/luckysheet.umd.js` + +If it is not convenient to access jsdelivr.net, you can also import it locally + +#### Import locally +After `npm run build`, all files in the `dist` folder are copied to the project directory ```html @@ -124,12 +138,12 @@ Introduce dependencies ``` -### Third step +### Second step Specify a table container ```html
``` -### Fourth step +### Third step Create a table ```javascript + +``` + +注意,`https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js`这个路径会拉取到最新的luckysheet代码,想要指定luckysheet版本,请在luckysheet后面加上版本号,如:`https://cdn.jsdelivr.net/npm/luckysheet@2.0.0/dist/luckysheet.umd.js` + +如果不方便访问 jsdelivr.net,还可以采用本地方式引入 + +#### 本地引入 + +`npm run build`后`dist`文件夹下的所有文件复制到项目目录,然后通过相对路径引入 -### 第二步 -引入依赖 ```html @@ -124,12 +139,12 @@ npm run build ``` -### 第三步 +### 第二步 指定一个表格容器 ```html
``` -### 第四步 +### 第三步 创建一个表格 ```javascript