• HTML+JavaScript画函数图像


    <!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="Delete(this.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 = function(ob) {
    			mouseX = ob.layerX;
    			mouseY = ob.layerY;
    			funStage = 1;
    		}
    		CANVAS.onmousemove = function(ob) {
    			if(funStage != 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 = function(ob) {
    			if(funStage == 1) {
    				funStage = 0;
    				reDraw();
    			}
    		}
    		CANVAS.onmouseleave = function(ob) {
    			if(funStage == 1) {
    				funStage = 0;
    				reDraw();
    			}
    		}
    		CANVAS.onmousewheel = function(ob) {
    			// 取消事件的默认动作
    			ob.preventDefault();
    			// 放大的比例
    			var ScaleRate = 0.9;
    			var detail;
    			if(ob.wheelDelta) {
    				detail = ob.wheelDelta;
    			} else if(ob.detail) {
    				detail = ob.detail;
    			}
    			if(detail > 0) {
    				scale(ob.layerX, FUN_IMG_HEIGHT - 1 - ob.layerY, ScaleRate);
    			} else {
    				scale(ob.layerX, FUN_IMG_HEIGHT - 1 - ob.layerY, 1 / ScaleRate);
    			}
    			reDraw();
    			update();
    		}
    		// 初始化
    		reDraw();
    		update();
    		Add();
    	</script>
    
    </html>
    

    funcImg.js

    function $(id) {
    	return document.getElementById(id);
    }
    
    function getRandomColor() {
    	var color = '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).substr(-6);
    	return color;
    }
    
    function FunWork(f, x) {
    	switch(f) {
    		case "":
    			{
    				return x;
    				break;
    			}
    		case "sin":
    			{
    				return Math.sin(x);
    				break;
    			}
    		case "cos":
    			{
    				return Math.cos(x);
    				break;
    			}
    		case "tan":
    			{
    				return Math.tan(x);
    				break;
    			}
    		case "abs":
    			{
    				return Math.abs(x);
    				break;
    			}
    		case "sqrt":
    			{
    				return Math.sqrt(x);
    				break;
    			}
    		case "ln":
    			{
    				return Math.log(x);
    				break;
    			}
    		case "log":
    			{
    				return Math.log(x) / Math.LN2;
    				break;
    			} //2为底
    		case "lg":
    			{
    				return Math.log(x) / Math.LN10;
    				break;
    			} //10为底
    		case "floor":
    			{
    				return Math.floor(x);
    				break;
    			}
    		case "ceil":
    			{
    				return Math.ceil(x);
    				break;
    			}
    		case "int":
    			{
    				return parseInt(x);
    				break;
    			}
    		default:
    			{
    				return NaN;
    				break;
    			}
    	}
    }
    
    function ChangeToPointY(y) {
    	return FUN_IMG_HEIGHT - 1 - parseInt((y - yLeftValue) / (yRightValue - yLeftValue) * FUN_IMG_HEIGHT);
    }
    
    function isChar(c) {
    	return(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
    }
    
    function isDigit(c) {
    	return c >= '0' && c <= '9';
    }
    
    function priority(c) {
    	switch(c) {
    		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 isOpt(c) {
    	return priority(c) != -1;
    }
    
    function singleCalc(c, a, b) {
    	if(c == '+') {
    		return a + b;
    	} else
    	if(c == '-') {
    		return a - b;
    	} else
    	if(c == '*') {
    		return a * b;
    	} else
    	if(c == '/') {
    		return a / b;
    	} else
    	if(c == '^') {
    		return Math.pow(a, b);
    	} else {
    		return NaN;
    	}
    }
    
    function getTable() {
    	tmp = (xRightValue - xLeftValue + EPS) / 20;
    
    	tableX = 1;
    	countX = 0;
    	countY = 0;
    	while(tableX < tmp) {
    		tableX *= 10;
    	}
    	while(tableX / 10 > tmp) {
    		tableX /= 10;
    		countX++;
    	}
    	if(tableX >= 1) {
    		countX = 0;
    	}
    	if(tableX / 5 > tmp) {
    		tableX /= 5;
    		countX++;
    	} else if(tableX / 2 > tmp) {
    		tableX /= 2;
    		countX++;
    	}
    	var i = parseInt(xLeftValue / tableX) + (xLeftValue > 0)
    	for(; i * tableX < xRightValue; i++) {
    		if(i == 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.fillRect(tmp, 0, _width, _height);
    		// 竖线上的数字
    		CONTEXT_2D.fillStyle = "red";
    		CONTEXT_2D.font = FONT_STYLE;
    		var _text = (i * tableX).toFixed(countX);
    		var _x = tmp + 2;
    		var _y = 10;
    		CONTEXT_2D.fillText(_text, _x, _y);
    	}
    	tmp = (yRightValue - yLeftValue + EPS) / 20;
    	tableY = 1;
    
    	while(tableY < tmp) {
    		tableY *= 10;
    	}
    	while(tableY / 10 > tmp) {
    		tableY /= 10, countY++;
    	}
    	if(tableY / 5 > tmp) {
    		tableY /= 5, countY++;
    	} else if(tableY / 2 > tmp) {
    		tableY /= 2, countY++;
    	}
    	if(tableY >= 1) {
    		countY = 0;
    	}
    	var i = parseInt(yLeftValue / tableY) + (yLeftValue > 0);
    	for(; i * tableY < yRightValue; i++) {
    		// 横线
    		if(i == 0) {
    			// x轴
    			CONTEXT_2D.fillStyle = "black";
    		} else {
    			// 普通横线
    			CONTEXT_2D.fillStyle = "#CDB7B5";
    		}
    		tmp = (i * tableY - yLeftValue) / (yRightValue - yLeftValue) * FUN_IMG_HEIGHT;
    		CONTEXT_2D.fillRect(0, FUN_IMG_HEIGHT - 1 - tmp, FUN_IMG_WIDTH, 1);
    		// 横线上的数字
    		CONTEXT_2D.fillStyle = "blue";
    		CONTEXT_2D.font = FONT_STYLE;
    		CONTEXT_2D.fillText((i * tableY).toFixed(countY), 0, FUN_IMG_HEIGHT - 1 - tmp);
    	}
    }
    
    function drawArc(x, y) {
    	CONTEXT_2D.beginPath();
    	// arc(弧形),画圆
    	CONTEXT_2D.arc(x, y, 1, 0, Math.PI * 2);
    	CONTEXT_2D.closePath();
    	CONTEXT_2D.fill();
    }
    
    function drawLine(lx, ly, px, py) {
    	CONTEXT_2D.beginPath();
    	CONTEXT_2D.moveTo(lx, ly);
    	CONTEXT_2D.lineTo(px, py);
    	CONTEXT_2D.closePath();
    	CONTEXT_2D.stroke(); // 绘制
    }
    
    function reDraw() {
    	CONTEXT_2D.clearRect(0, 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 scale(x, y, times) {
    	if(x < 0 || x >= FUN_IMG_WIDTH || y < 0 || y >= FUN_IMG_HEIGHT) return;
    
    	if(times < 1 && (xRightValue - xLeftValue < MIN || yRightValue - yLeftValue < MIN)) {
    		return;
    	}
    	if(times > 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 Calc(fun, X, Value) {
    	var number = new Array(),
    		opt = new Array(),
    		F = new Array(),
    		now = 0,
    		f = "",
    		tmp, a, b, sign = 1,
    		base = 0,
    		j;
    	for(var i = 0; i < fun.length; i++) {
    		for(j = 0; j < X.length; j++)
    			if(X[j] == fun[i]) {
    				if(i == 0 || isOpt(fun[i - 1])) now = Value[j];
    				else now *= Value[j];
    				break;
    			}
    		if(j == X.length)
    			if(fun[i] == '(') F.push(f), f = "", opt.push('(');
    			else
    		if(fun[i] == ')') {
    			number.push(now * sign);
    			now = 0;
    			sign = 1;
    			base = 0;
    			while((tmp = opt.pop()) != '(') {
    				b = number.pop();
    				a = number.pop();
    				tmp = singleCalc(tmp, a, b);
    				number.push(tmp);
    			}
    			now = FunWork(F.pop(), number.pop());
    		} else
    		if(fun[i] == '.') base = 1;
    		else
    		if(fun[i] == '+' && (i == 0 || priority(fun[i - 1]) != -1));
    		else
    		if(fun[i] == '-' && (i == 0 || priority(fun[i - 1]) != -1)) sign = -1;
    		else
    		if(fun[i] == 'e')
    			if(i == 0 || isOpt(fun[i - 1])) now = Math.E;
    			else now *= Math.E;
    		else
    		if(fun[i] == 'p' && fun[i + 1] == 'i') {
    			if(i == 0 || isOpt(fun[i - 1])) now = Math.PI;
    			else now *= Math.PI;
    			i += 1;
    		} else
    		if(isDigit(fun[i]))
    			if(base == 0) now = now * 10 + (fun[i] - '0');
    			else base /= 10, now += base * (fun[i] - '0');
    		else
    		if(isChar(fun[i])) f += fun[i];
    		else if(isOpt(fun[i])) {
    			number.push(now * sign);
    			now = 0;
    			sign = 1;
    			base = 0;
    			var s = priority(fun[i]);
    			if(s == -1) return 0;
    			while(s <= priority(opt[opt.length - 1])) {
    				b = number.pop();
    				a = number.pop();
    				tmp = singleCalc(opt.pop(), a, b);
    				number.push(tmp);
    			}
    			opt.push(fun[i]);
    		}
    	}
    	number.push(now * sign);
    	while(opt.length > 0) {
    		b = number.pop();
    		a = number.pop();
    		tmp = singleCalc(opt.pop(), a, b);
    		number.push(tmp);
    	}
    	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;
    
    	for(var 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;
    
    		for(var i = 0; i < FUN_IMG_WIDTH; i++) {
    			x = xLeftValue + (xRightValue - xLeftValue) / FUN_IMG_WIDTH * i;
    			y = Calc(funcExpression, ['x'], [x]);
    			if(isNaN(y)) {
    				continue;
    			}
    			px = i;
    			py = ChangeToPointY(y);
    			if(y >= yLeftValue && y < yRightValue) {
    				// 画圆
    				drawArc(px, py);
    				if(isDrawLine) {
    					drawLine(lax, lay, px, py);
    				}
    				outSide = 0;
    			} else {
    				if(isDrawLine) {
    					if(!outSide) {
    						drawLine(lax, lay, px, py);
    					}
    				} else {}
    				outSide = 1;
    			}
    			lax = px;
    			lay = py;
    		}
    	}
    }
    
    function Add() {
    	var newInput = $("mod").cloneNode(true);
    	newInput.style.display = "block";
    	newInput.children[0].value = getRandomColor();
    	$("function").appendChild(newInput);
    }
    
    function Delete(node) {
    	node.parentNode.removeChild(node);
    }
    
  • 相关阅读:
    深入解析QML引擎,第1部分:QML文件加载
    解释器原理
    NLP入门(十)使用LSTM进行文本情感分析
    Python之将Python字符串生成PDF
    SPARQL入门(二)使用Java操作ARQ
    SPARQL入门(一)SPARQL简介与简单使用
    NLP入门(九)词义消岐(WSD)的简介与实现
    利用百度文字识别API识别图像中的文字
    NLP入门(八)使用CRF++实现命名实体识别(NER)
    Cayley图数据库的可视化(Visualize)
  • 原文地址:https://www.cnblogs.com/tigerlion/p/12072713.html
Copyright © 2020-2023  润新知