zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    springboot文件上传: 单个文件上传 和 多个文件上传
    Eclipse:很不错的插件-devStyle,将你的eclipse变成idea风格
    springboot项目搭建:结构和入门程序
    POJ 3169 Layout 差分约束系统
    POJ 3723 Conscription 最小生成树
    POJ 3255 Roadblocks 次短路
    UVA 11367 Full Tank? 最短路
    UVA 10269 Adventure of Super Mario 最短路
    UVA 10603 Fill 最短路
    POJ 2431 Expedition 优先队列
  • 原文地址:https://www.cnblogs.com/tigerlion/p/12072713.html
Copyright © 2011-2022 走看看