<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>函数图像绘制工具</title>
<script type="text/javascript" src="js/funcImg.js"></script>
<style>
#div-img {
/* 此决定画布的宽高 */
500px;
height: 500px;
}
#input-controller {
padding: 10px;
background-color: azure;
}
</style>
</head>
<body>
<div id="input-controller">
<div id="function">
<button onclick="Add)">添加函数</button>
<span id="mod" style="display:none" name="0">
<input type="color"/>y=
<input type="text" value="x^3" name="Fun"/>
<button onclick="Deletethis.parentNode)">Delete</button>
<input type="checkbox" onclick="reDraw)" checked="checked"/>Draw Line
</span>
</div>
<div id="option">
X:<input id="xLeftValue" /> ~
<input id="xRightValue" />
<br> Y:
<input id="yLeftValue" /> ~
<input id="yRightValue" />
<br>
<span id="show-size">Size:</span>
</div>
<button onclick="change)">画图</button>
</div>
<div id="main">
<h1>函数图像绘制工具</h1>
<div id="div-img">
<canvas id="graph"></canvas>
</div>
</div>
</body>
<script>
const FONT_STYLE = "10px 黑体";
const MIN = 1e-4;
const MAX = 1e8;
const EPS = 1e-12;
const CANVAS = $"graph");
const CONTEXT_2D = CANVAS.getContext"2d");
const FUN_IMG_WIDTH = CANVAS.parentNode.clientWidth;
const FUN_IMG_HEIGHT = CANVAS.parentNode.clientHeight;
var xLeftValue = -FUN_IMG_WIDTH / 100; // x最左的值
var xRightValue = FUN_IMG_WIDTH / 100;
var yLeftValue = -FUN_IMG_HEIGHT / 100;
var yRightValue = FUN_IMG_HEIGHT / 100;
var tableX, tableY, countX, countY;
var funStage = 0,
mouseX, mouseY;
var tmp;
</script>
<script>
CANVAS.width = FUN_IMG_WIDTH;
CANVAS.height = FUN_IMG_HEIGHT;
$"show-size").innerHTML = "Size:" + FUN_IMG_WIDTH + "*" + FUN_IMG_HEIGHT;
CANVAS.onmousedown = functionob) {
mouseX = ob.layerX;
mouseY = ob.layerY;
funStage = 1;
}
CANVAS.onmousemove = functionob) {
iffunStage != 1) {
return;
}
var NoX, NoY, det;
NoX = ob.layerX;
NoY = ob.layerY;
det = mouseX - NoX) / FUN_IMG_WIDTH * xRightValue - xLeftValue);
xLeftValue += det;
xRightValue += det;
det = NoY - mouseY) / FUN_IMG_HEIGHT * yRightValue - yLeftValue);
yLeftValue += det;
yRightValue += det;
mouseX = NoX;
mouseY = NoY;
reDraw);
update);
}
CANVAS.onmouseup = functionob) {
iffunStage == 1) {
funStage = 0;
reDraw);
}
}
CANVAS.onmouseleave = functionob) {
iffunStage == 1) {
funStage = 0;
reDraw);
}
}
CANVAS.onmousewheel = functionob) {
// 取消事件的默认动作
ob.preventDefault);
// 放大的比例
var ScaleRate = 0.9;
var detail;
ifob.wheelDelta) {
detail = ob.wheelDelta;
} else ifob.detail) {
detail = ob.detail;
}
ifdetail > 0) {
scaleob.layerX, FUN_IMG_HEIGHT - 1 - ob.layerY, ScaleRate);
} else {
scaleob.layerX, FUN_IMG_HEIGHT - 1 - ob.layerY, 1 / ScaleRate);
}
reDraw);
update);
}
// 初始化
reDraw);
update);
Add);
</script>
</html>
funcImg.js
function $id) {
return document.getElementByIdid);
}
function getRandomColor) {
var color = '#' + '00000' + Math.random) * 0x1000000 << 0).toString16)).substr-6);
return color;
}
function FunWorkf, x) {
switchf) {
case "":
{
return x;
break;
}
case "sin":
{
return Math.sinx);
break;
}
case "cos":
{
return Math.cosx);
break;
}
case "tan":
{
return Math.tanx);
break;
}
case "abs":
{
return Math.absx);
break;
}
case "sqrt":
{
return Math.sqrtx);
break;
}
case "ln":
{
return Math.logx);
break;
}
case "log":
{
return Math.logx) / Math.LN2;
break;
} //2为底
case "lg":
{
return Math.logx) / Math.LN10;
break;
} //10为底
case "floor":
{
return Math.floorx);
break;
}
case "ceil":
{
return Math.ceilx);
break;
}
case "int":
{
return parseIntx);
break;
}
default:
{
return NaN;
break;
}
}
}
function ChangeToPointYy) {
return FUN_IMG_HEIGHT - 1 - parseInty - yLeftValue) / yRightValue - yLeftValue) * FUN_IMG_HEIGHT);
}
function isCharc) {
returnc >= 'a' && c <= 'z') || c >= 'A' && c <= 'Z');
}
function isDigitc) {
return c >= '0' && c <= '9';
}
function priorityc) {
switchc) {
case '':
return 0;
break;
case '+':
return 1;
break;
case '-':
return 1;
break;
case '*':
return 2;
break;
case '/':
return 2;
break;
case '^':
return 3;
break;
default:
return -1;
break;
}
}
// 是运算符
function isOptc) {
return priorityc) != -1;
}
function singleCalcc, a, b) {
ifc == '+') {
return a + b;
} else
ifc == '-') {
return a - b;
} else
ifc == '*') {
return a * b;
} else
ifc == '/') {
return a / b;
} else
ifc == '^') {
return Math.powa, b);
} else {
return NaN;
}
}
function getTable) {
tmp = xRightValue - xLeftValue + EPS) / 20;
tableX = 1;
countX = 0;
countY = 0;
whiletableX < tmp) {
tableX *= 10;
}
whiletableX / 10 > tmp) {
tableX /= 10;
countX++;
}
iftableX >= 1) {
countX = 0;
}
iftableX / 5 > tmp) {
tableX /= 5;
countX++;
} else iftableX / 2 > tmp) {
tableX /= 2;
countX++;
}
var i = parseIntxLeftValue / tableX) + xLeftValue > 0)
for; i * tableX < xRightValue; i++) {
ifi == 0) {
// y轴
CONTEXT_2D.fillStyle = "black";
} else {
// 普通竖线
CONTEXT_2D.fillStyle = "#CDB7B5";
}
tmp = i * tableX - xLeftValue) / xRightValue - xLeftValue) * FUN_IMG_WIDTH;
var _width = 1;
var _height = FUN_IMG_HEIGHT;
CONTEXT_2D.fillRecttmp, 0, _width, _height);
// 竖线上的数字
CONTEXT_2D.fillStyle = "red";
CONTEXT_2D.font = FONT_STYLE;
var _text = i * tableX).toFixedcountX);
var _x = tmp + 2;
var _y = 10;
CONTEXT_2D.fillText_text, _x, _y);
}
tmp = yRightValue - yLeftValue + EPS) / 20;
tableY = 1;
whiletableY < tmp) {
tableY *= 10;
}
whiletableY / 10 > tmp) {
tableY /= 10, countY++;
}
iftableY / 5 > tmp) {
tableY /= 5, countY++;
} else iftableY / 2 > tmp) {
tableY /= 2, countY++;
}
iftableY >= 1) {
countY = 0;
}
var i = parseIntyLeftValue / tableY) + yLeftValue > 0);
for; i * tableY < yRightValue; i++) {
// 横线
ifi == 0) {
// x轴
CONTEXT_2D.fillStyle = "black";
} else {
// 普通横线
CONTEXT_2D.fillStyle = "#CDB7B5";
}
tmp = i * tableY - yLeftValue) / yRightValue - yLeftValue) * FUN_IMG_HEIGHT;
CONTEXT_2D.fillRect0, FUN_IMG_HEIGHT - 1 - tmp, FUN_IMG_WIDTH, 1);
// 横线上的数字
CONTEXT_2D.fillStyle = "blue";
CONTEXT_2D.font = FONT_STYLE;
CONTEXT_2D.fillTexti * tableY).toFixedcountY), 0, FUN_IMG_HEIGHT - 1 - tmp);
}
}
function drawArcx, y) {
CONTEXT_2D.beginPath);
// arc弧形),画圆
CONTEXT_2D.arcx, y, 1, 0, Math.PI * 2);
CONTEXT_2D.closePath);
CONTEXT_2D.fill);
}
function drawLinelx, ly, px, py) {
CONTEXT_2D.beginPath);
CONTEXT_2D.moveTolx, ly);
CONTEXT_2D.lineTopx, py);
CONTEXT_2D.closePath);
CONTEXT_2D.stroke); // 绘制
}
function reDraw) {
CONTEXT_2D.clearRect0, 0, FUN_IMG_WIDTH, FUN_IMG_HEIGHT);
getTable);
getFunction);
}
function change) {
xLeftValue = parseFloat$"xLeftValue").value);
xRightValue = parseFloat$"xRightValue").value);
yLeftValue = parseFloat$"yLeftValue").value);
yRightValue = parseFloat$"yRightValue").value);
reDraw);
}
function update) {
$"xLeftValue").value = xLeftValue;
$"xRightValue").value = xRightValue;
$"yLeftValue").value = yLeftValue;
$"yRightValue").value = yRightValue;
}
function scalex, y, times) {
ifx < 0 || x >= FUN_IMG_WIDTH || y < 0 || y >= FUN_IMG_HEIGHT) return;
iftimes < 1 && xRightValue - xLeftValue < MIN || yRightValue - yLeftValue < MIN)) {
return;
}
iftimes > 1 && xRightValue - xLeftValue > MAX || yRightValue - yLeftValue > MAX)) {
return;
}
x = xLeftValue + xRightValue - xLeftValue) / FUN_IMG_WIDTH * x;
y = yLeftValue + yRightValue - yLeftValue) / FUN_IMG_HEIGHT * y;
xLeftValue = x - x - xLeftValue) * times;
xRightValue = x + xRightValue - x) * times;
yLeftValue = y - y - yLeftValue) * times;
yRightValue = y + yRightValue - y) * times;
}
function Calcfun, X, Value) {
var number = new Array),
opt = new Array),
F = new Array),
now = 0,
f = "",
tmp, a, b, sign = 1,
base = 0,
j;
forvar i = 0; i < fun.length; i++) {
forj = 0; j < X.length; j++)
ifX[j] == fun[i]) {
ifi == 0 || isOptfun[i - 1])) now = Value[j];
else now *= Value[j];
break;
}
ifj == X.length)
iffun[i] == '') F.pushf), f = "", opt.push'');
else
iffun[i] == ')') {
number.pushnow * sign);
now = 0;
sign = 1;
base = 0;
whiletmp = opt.pop)) != '') {
b = number.pop);
a = number.pop);
tmp = singleCalctmp, a, b);
number.pushtmp);
}
now = FunWorkF.pop), number.pop));
} else
iffun[i] == '.') base = 1;
else
iffun[i] == '+' && i == 0 || priorityfun[i - 1]) != -1));
else
iffun[i] == '-' && i == 0 || priorityfun[i - 1]) != -1)) sign = -1;
else
iffun[i] == 'e')
ifi == 0 || isOptfun[i - 1])) now = Math.E;
else now *= Math.E;
else
iffun[i] == 'p' && fun[i + 1] == 'i') {
ifi == 0 || isOptfun[i - 1])) now = Math.PI;
else now *= Math.PI;
i += 1;
} else
ifisDigitfun[i]))
ifbase == 0) now = now * 10 + fun[i] - '0');
else base /= 10, now += base * fun[i] - '0');
else
ifisCharfun[i])) f += fun[i];
else ifisOptfun[i])) {
number.pushnow * sign);
now = 0;
sign = 1;
base = 0;
var s = priorityfun[i]);
ifs == -1) return 0;
whiles <= priorityopt[opt.length - 1])) {
b = number.pop);
a = number.pop);
tmp = singleCalcopt.pop), a, b);
number.pushtmp);
}
opt.pushfun[i]);
}
}
number.pushnow * sign);
whileopt.length > 0) {
b = number.pop);
a = number.pop);
tmp = singleCalcopt.pop), a, b);
number.pushtmp);
}
return number.pop);
}
function getFunction) {
// group:函数(可能是复数)
var group = document.getElementsByName"Fun");
var x, y;
var lax, lay;
var px, py
var color, outSide, type
var ValueL, ValueR, ValueS, isDrawLine, tmp, TMP;
forvar k = 1; k < group.length; k++) {
var _funcItem = group[k].parentNode;
outSide = 1;
//type = _funcItem.children[0].value;
// 颜色
color = _funcItem.children[0].value;
// 函数表达式
funcExpression = group[k].value;
// 是否画线(默认画点)
isDrawLine = _funcItem.children[3].checked;
CONTEXT_2D.fillStyle = CONTEXT_2D.strokeStyle = color;
forvar i = 0; i < FUN_IMG_WIDTH; i++) {
x = xLeftValue + xRightValue - xLeftValue) / FUN_IMG_WIDTH * i;
y = CalcfuncExpression, ['x'], [x]);
ifisNaNy)) {
continue;
}
px = i;
py = ChangeToPointYy);
ify >= yLeftValue && y < yRightValue) {
// 画圆
drawArcpx, py);
ifisDrawLine) {
drawLinelax, lay, px, py);
}
outSide = 0;
} else {
ifisDrawLine) {
if!outSide) {
drawLinelax, lay, px, py);
}
} else {}
outSide = 1;
}
lax = px;
lay = py;
}
}
}
function Add) {
var newInput = $"mod").cloneNodetrue);
newInput.style.display = "block";
newInput.children[0].value = getRandomColor);
$"function").appendChildnewInput);
}
function Deletenode) {
node.parentNode.removeChildnode);
}