是否有一个javascript库可以在没有UI的情况下进行电子表格计算

时间:2016-03-04 10:51:16

标签: javascript excel spreadsheet

我正在开发一个需要在浏览器中使用像计算引擎这样的excel的项目。但是,它不需要网格UI。

目前,我可以隐藏' div' Handsontable的元素。但是,它并不优雅。它也有点慢。

javascript中是否有客户端电子表格计算库可以执行此类操作?

x = [ [1, 2, "=A1+B1"],
      [2, "=SUM(A1,A2"),3] ];

y = CalculateJS(x);

##############
y: [[1, 2, 3], 
[2,3,3]]

2 个答案:

答案 0 :(得分:0)

我不知道(虽然我没有真正看过),但是如果你想实现自己的,你可以沿着这些方向做一些事情(严重未经优化,没有错误检查):< / p>

functions = {
    SUM: function(args) {
        var result = 0;
        for (var i = 0; i < args.length; i++) {
            result += parseInt(args[i]);
        }
        return result;
    }
};

function get_cell(position) {
    // This function returns the value of a cell at `position`
}

function parse_cell(position) {
    cell = get_cell(position);

    if (cell.length < 1 || cell[0] !== '=')
        return cell;

    return parse_token(cell.slice(1));
}

function parse_token(tok) {
    tok = tok.trim();

    if (tok.indexOf("(") < 0)
        return parse_cell(tok);

    var name = tok.slice(0, tok.indexOf("("));

    if (!(name in functions)) {
        return 0; // something better than this?
    }

    var arguments_tok = tok.slice(tok.indexOf("(") + 1);
    var arguments = [];

    while (true) {
        var arg_end = arguments_tok.indexOf(",");
        if (arg_end < 0) {
            arg_end = arguments_tok.lastIndexOf(")");
            if (arg_end < 0)
                break;
        }

        if (arguments_tok.indexOf("(") >= 0 && (arguments_tok.indexOf("(") < arg_end)) {
            var paren_amt = 1;
            arg_end = arguments_tok.indexOf("(") + 1;
            var end_tok = arguments_tok.slice(arguments_tok.indexOf("(") + 1);
            while (true) {
                if (paren_amt < 1) {
                    var last_index = end_tok.indexOf(",");
                    if (last_index < 0)
                        last_index = end_tok.indexOf(")");
                    arg_end += last_index;
                    end_tok = end_tok.slice(last_index);
                    break;
                }
                if (end_tok.indexOf("(") > 0 && (end_tok.indexOf("(") < end_tok.indexOf(")"))) {
                    paren_amt++;
                    arg_end += end_tok.indexOf("(") + 1;
                    end_tok = end_tok.slice(end_tok.indexOf("(") + 1);
                } else {
                    arg_end += end_tok.indexOf(")") + 1;
                    end_tok = end_tok.slice(end_tok.indexOf(")") + 1);
                    paren_amt--;
                }
            }
        }

        arguments.push(parse_token(arguments_tok.slice(0, arg_end)));

        arguments_tok = arguments_tok.slice(arg_end + 1);
    }

    return functions[name](arguments);
}

希望这会给你一个起点!

要在浏览器中进行测试,请将get_cell设置为function get_cell(x) {return x;},然后运行parse_cell("=SUM(5,SUM(1,7,SUM(8,111)),7,8)")。它应该导致147:)

答案 1 :(得分:0)

我设法用bacon.js做到了这一点。它解释了细胞的相互依赖性。截至目前,它通过使用eval函数计算javascript公式的值而不是excel公式。为了使它适用于excel公式,所有人必须做的是用Handsontable的ruleJS库替换eval。我无法找到该库的URI ...因此eval。

https://jsfiddle.net/sandeep_muthangi/3src81n3/56/

var mx = [[1, 2, "A1+A2"],
        [2, "A2", "A3"]];

var output_reference_bus = {};

var re = /\$?[A-N]{1,2}\$?[1-9]{1,4}/ig
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');

function convertToCellRef(rows, cols)   {
    var alphabet_index = rows+1, 
        abet = "";

  while (alphabet_index>0)  {
    abet = alphabet[alphabet_index%alphabet.length-1]+abet;
    alphabet_index = Math.floor(alphabet_index/alphabet.length);
  }

  return abet+(cols+1).toString();
}

function getAllReferences(value)    {
    if (typeof value != "string")
    return null;
  var references = value.match(re)
  if (references.length == 0)
    return null;
  return references;   
}

function replaceReferences(equation, args)  {
    var index = 0;
    return equation.replace(re, function(match, x, string)  {       
      return args[index++];
  });
}

//Assign an output bus to each cell
mx.forEach(function(row, row_index) {
    row.forEach(function(cell, cell_index)  {
    output_reference_bus[convertToCellRef(row_index, cell_index)] = Bacon.Bus();    
  })
})

//assign input buses based on cell references... and calculate the result when there is a value on all input buses
mx.forEach(function(row, row_index) {
    row.forEach(function(cell, cell_index)  {    
    if ((all_refs = getAllReferences(cell)) != null)    {

        var result = Bacon.combineAsArray(output_reference_bus[all_refs[0]]);

      for (i=1; i<all_refs.length; i++) {           
        result = Bacon.combineAsArray(result, output_reference_bus[all_refs[i]]);
      }

      result = result.map(function(data)    {           
            return eval(replaceReferences(cell, data));
      })      

      result.onValue(function(data) {
        console.log(convertToCellRef(row_index, cell_index), data);
        output_reference_bus[convertToCellRef(row_index, cell_index)].push(data);        
      });
    }

   else {
    if (typeof cell != "string")
      output_reference_bus[convertToCellRef(row_index, cell_index)].push(cell);          
    else        
      output_reference_bus[convertToCellRef(row_index, cell_index)].push(eval(cell));
   }
  })
})

output_reference_bus["A2"].push(20);
output_reference_bus["A1"].push(1);
output_reference_bus["A1"].push(50);