需要用到几天前写的Mathast,或者修改一下用eval也可以。
必要说明:

id 为canvas的id
exp 为函数 (如sin X 大写X为自变量)
color 为颜色(若不存在会自动生成)
max_x / max_y 为图像显示域,若分别输入10和20,则显示的范围为X∈[-10, 10] Y∈[-20, 20]

用法:

draw('c', 'sin X', '#272727', 4*Math.PI, 3);

注意:Y=2X+5等函数应该写成2*X+5,应遵守Mathast的语法原则。还有部分函数由于取值问题使曲线没有连接到位,请脑部 :)

正态分布表达式: pow E (-squ(X)/2*squ10) / sqr(2*PI) * 10

下图为tanXX*sinX+cosX (不同域下) 的图像

函数图像

在线实例:foxnes.github.com/mathexp.html

上代码:

function draw(id, exp, color, max_x){
  if (typeof color == 'undefined' || color == '') {
    var color = (function(m, s, c) {return (c ? arguments.callee(m, s, c - 1) : '#') + s[m.floor(m.random() * 16)]})(Math, '0123456789abcdef', 5);
  }
  if (typeof max_x == 'undefined' || max_x == 0 || max_x == '') {
    var max_x = 10;
  }
  function transcoo(x, y) {
    return {
      x: ((w / 2) + (x * division_x)),
      y: ((h / 2) - (y * division_y))
    };
  }
  var c = document.getElementById(id),
  ctx = c.getContext('2d');
  if (exp == false) {
    ctx.clearRect(0,0,c.width,c.height);
    return true;
  }
  var w = c.width,
  h = c.height,
  division_x = w / max_x,
  division_y = h / max_x,
  sort = [],
  sort_ = [],
  tmp,
  tmp_,
  trend = ['asc', 0],
  index = 0,
  addx = max_x / 150,
  sign_ = false,
  calc = {
  Add: function (arg1, arg2) {
   arg1 = arg1.toString();
   arg2 = arg2.toString();
   var arg1Arr = arg1.split("."), arg2Arr = arg2.split("."), d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", d2 = arg2Arr.length == 2 ? arg2Arr[1] : "";
   var maxLen = Math.max(d1.length, d2.length);
   var m = Math.pow(10, maxLen);
   var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen));
   var d = arguments[2];
   return typeof d === "number" ? Number((result).toFixed(d)) : result;
  },
  Sub: function (arg1, arg2) {
   return calc.Add(arg1, -Number(arg2), arguments[2]);
  },
  Mul: function (arg1, arg2) {
   var r1 = arg1.toString(), r2 = arg2.toString(), m, resultVal, d = arguments[2];
   m = (r1.split(".")[1] ? r1.split(".")[1].length : 0) + (r2.split(".")[1] ? r2.split(".")[1].length : 0);
   resultVal = Number(r1.replace(".", "")) * Number(r2.replace(".", "")) / Math.pow(10, m);
   return typeof d !== "number" ? Number(resultVal) : Number(resultVal.toFixed(parseInt(d)));
  },
  Div: function (arg1, arg2) {
   var r1 = arg1.toString(), r2 = arg2.toString(), m, resultVal, d = arguments[2];
   m = (r2.split(".")[1] ? r2.split(".")[1].length : 0) - (r1.split(".")[1] ? r1.split(".")[1].length : 0);
   resultVal = Number(r1.replace(".", "")) / Number(r2.replace(".", "")) * Math.pow(10, m);
   return typeof d !== "number" ? Number(resultVal) : Number(resultVal.toFixed(parseInt(d)));
  }
};
  ctx.beginPath();
  ctx.strokeStyle = "#0f0f0f";
  ctx.lineWidth = 1;
  ctx.moveTo(w / 2, 0);
  ctx.lineTo(w / 2, h);
  ctx.moveTo(0, h / 2);
  ctx.lineTo(w, h / 2);
  ctx.stroke();
  ctx.closePath();
  ctx.beginPath();
  ctx.strokeStyle = color;
  ctx.lineWidth = 2;
  var i = calc.Div(-max_x, 2);
  while ( i <= calc.Div(max_x, 2) ) {
    tmp = Mathast.run(exp.replace(/x/ig, '(' + i + ')')).result.value;
    if (typeof tmp == 'number' && !isNaN(tmp)) {
      sort.push({
          y: Number(tmp),
          x: Number(i)
      });
      if (index > 0)
        tmp_ = calc.Sub(sort[(index - 1)].y, sort[index].y);
      else
        tmp_ = false;
      if (tmp_ <= 0 && trend[0] == 'desc' && tmp_ !== false) {
        trend = ['asc', tmp_];
        tmp_ = true;
      }else if (tmp_ >= 0 && trend[0] == 'asc' && tmp_ !== false){
        trend = ['desc', tmp_];
        tmp_ = true;
      }else{
        tmp_ = false;
      }
      if (tmp_ !== true) {
        if (index - 2 >= 0){
          tmp = calc.Div(calc.Sub(sort[(index - 2)].y, sort[(index - 1)].y), 2);
          tmp_ = calc.Sub(sort[(index - 1)].y, sort[index].y);
        }else{
          tmp = 0;
          tmp_ = 0;
        }
        if (Math.abs(tmp_) > Math.abs(tmp)){
          tmp_ = true;
        }else{
          tmp_ = false;
        }
      }
      if (tmp_ !== false) {
        for (var j = sort[(index - 1)].x; j <= sort[index].x; j = calc.Add(j, calc.Div(addx, 50))) {
          tmp = Mathast.run(exp.replace(/X/ig, '(' + j + ')')).result.value;
          if (typeof tmp == 'number' && !isNaN(tmp)){
            sort.push({
              y: Number(tmp),
              x: Number(j)
            });
          }else{
            i = calc.Add(i, calc.Div(addx, 50));
            continue;
          }
        }
      }
      index = sort.length;
    }else{
      i = calc.Add(i, calc.Div(addx, 50));
      continue;
    }
    i = calc.Add(i, addx);
  }
  sort.sort(function(a, b){
    return a.x - b.x;
  });
  for (var i = 0; i < sort.length; i++) {
    tmp = sort[i];
    tmp = transcoo(tmp.x, tmp.y);
    if (i > 0 && (Math.abs(tmp.y) < (c.height))){
      ctx.lineTo(tmp.x, tmp.y);
    }else{
      ctx.moveTo(tmp.x, tmp.y);
    }
    tmp_++;
  }
  ctx.stroke();
  console.log(sort.length)
  return {r: true, d: sort.length};
}