Assignment2: A calculator that implements front - and back-end interaction

-草甸- 2023-10-20 03:10:05

I. Introduction 

In this blog post, I will detail the implementation of the front - and back-end interactive Web calculator and show the final product.

I made this calculator can achieve addition, subtraction, multiplication, division, zero clearing, power and trigonometric function, exponential function, inverse trigonometric function and ans operations.

Link to the finished project code: Assignment2 codes in github

II. Basic information about the author

Course for This Assignment2301-MUSE社区-CSDN社区云
Assignment RequirementsSecond assignment-- Back-end separation calculator programming-CSDN社区
The Aim of This AssignmentImprove the function of calculator and realize front-end interaction
MU STU ID and FZU21126259_832101125

目录

I. Introduction 

II. Basic information about the author

III. PSP Table

IV. Finished product display

①Web developer model:

② Basic Function

③Trigonometric function

④Anti-trigonometric function

 ④ logarithmic function:

⑤ Find history records(the latest ten history records):

 V. Project design idea

①Front-end design ideas:

②Back-end design idea:

 VII. Code interpretation

①Front-end code interpretation

a. Java Script

b. HTML

c. Css

 ②Back-end Programming Implementation (Python)

VII. Project future outlook

VIII. reflections

IX. Reference material


III. PSP Table

PSP Table
PSPEstimated time (minutes)Actual time (minutes)
Planning  
• Estimate:4040
Development  
• Analysis3030
• Design Spec2020
• Design Review1010
• Coding Standard:2020
• Design3030
• Coding300500
• Code Review100100
• Test2030
Reporting  
• Test Report:55
• Size Measurement1010
• Postmortem & Process Improvement Plan1010
TOTAL TIME595805

IV. Finished Product Display

①Web developer model:

② Basic Function

 

③Trigonometric function

sin(x):

cos(x):

tan(x):

④ Anti-trigonometric function

 asin(x):

 

acos(x):

 

atan(x):

 

 ④ logarithmic function:

 

 

⑤ Find history records(the latest ten history records):

 


 V. Project design idea

①Front-end design ideas:

a. HTML Structure: Create an HTML file to define the structure of the web page. Add input fields, buttons, and other elements so that users can enter mathematical expressions and perform calculations.

b. CSS Styling: Use CSS to beautify your web pages and make them look attractive and easy to use. You can add styles such as backgrounds, fonts, colors, and layouts.

c. JavaScript interaction: Use JavaScript to write front-end logic that implements the following functions:

     Listen for button click events to capture user input.

     Dynamic display of user input mathematical expressions in the input box.

     Handles expression evaluation when the user clicks the equal button.

     Display the calculation results on the web page.

d. User Experience (UX) : Ensure that the user interface is friendly and easy to use. Error handling, such as division by zero error, inverse trigonometric function exceeding threshold error, etc. are added to improve user experience.

②Back-end design idea:

a. Python back end: Use Python to write back-end code, you can use PyCharm for development. The main role of the back end is to process requests from the front end, perform computation operations, and return the results to the front end.

b. API design: Design two apis, respectively for storage and reading.

c. Database connection: Store compute history or other data by using PyMySQL to connect to the database and perform the necessary database operations.

d. Result return: The stored expression and its corresponding calculation result are sent back to the front end, usually in JSON format. Be sure to handle any potential errors or exceptions to provide a friendly error message.

e. Deployment: Deploy the Python back-end to the local server to ensure that it can respond to front-end requests.


 VII. Code interpretation

①Front-end code interpretation

a. Java Script

// 这个函数用于将输入添加到显示框中
function display(input) {
  const str = document.getElementById("text");
  str.value += input;
}

// 这个异步函数执行计算,处理数学表达式
async function equals() {
  const str = document.getElementById("text");
  let input = str.value;
  let lastExpression = input;

  // 如果输入包含 'Ans',尝试获取答案并替换 'Ans' 为答案的值
  if (input.includes('Ans')) {
    try {
      const ansValue = await getAns();
      input = input.replace(/Ans/g, ansValue);
    } catch (error) {
      console.error('获取答案出错: ' + error);
    }
  }

  // 处理三角函数和反三角函数
  if (input.includes('asin') || input.includes('acos')) {
    const asinMatch = input.match(/asin\(([^)]+)\)/);
    const acosMatch = input.match(/acos\(([^)]+)\)/);

    if (asinMatch) {
      const x = parseFloat(asinMatch[1]);
      if (x < -1 || x > 1) {
        str.value = "Error: Invalid input for asin(x). x must be in the range [-1, 1].";
        return;
      }
    }

    if (acosMatch) {
      const x = parseFloat(acosMatch[1]);
      if (x < -1 || x > 1) {
        str.value = "Error: Invalid input for acos(x). x must be in the range [-1, 1].";
        return;
      }
    }
  }

  // 替换 '^' 运算符为 '**'
  if (input.includes('^')) {
    input = input.replace(/\^/g, '**');
  }

  // 替换三角函数和反三角函数为 Math 对象的方法
  if (input.includes('asin') || input.includes('acos') || input.includes('atan')) {
    input = input.replace(/(\b(asin|acos|atan))\(/g, 'Math.$2(');
  }

  // 替换 sin, cos, tan 为 Math.sin, Math.cos, Math.tan
  if (input.includes('sin') || input.includes('cos') || input.includes('tan')) {
    input = input.replace(/(\b(sin|cos|tan))\(/g, 'Math.$2(');
  }

  // 替换 'e' 为 Math.E,'π' 为 Math.PI
  if (input.includes('e')) {
    input = input.replace(/e/g, 'Math.E');
  }
  if (input.includes('π')) {
    input = input.replace(/π/g, 'Math.PI');
  }

  // 处理对数函数
  if (input.includes('log')) {
    input = input.replace(/log\(([^)]+)\)\(([^)]+)\)/g, 'Math.log($2) / Math.log($1)');
  }

  // 替换 'ln' 为 Math.log
  if (input.includes('ln')) {
    input = input.replace(/ln/g, 'Math.log');
  }

  // 替换 'Ans' 为上次计算的结果
  if (input.includes('Ans')) {
    let ansValue = getAns();
    input = input.replace(/Ans/g, ansValue);
  }

  // 处理除以 0 的情况
  if (input.includes('/0')) {
    str.value = "Error: Division by zero is not allowed";
    return;
  }

  try {
    // 使用 eval 函数计算表达式
    const result = eval(input);
    str.value = result;

    // 创建一个 XMLHttpRequest 对象并发送 POST 请求
    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://localhost:5000/post', true);
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          const response = xhr.responseText;
          console.log(response);
        } else {
          console.error('请求失败,状态码:' + xhr.status);
        }
      }
    };
    const data = {
      expression: lastExpression,
      result: result
    };
    xhr.send(JSON.stringify(data));
  } catch (error) {
    str.value = "Error";
  }
}

// 删除最后一个字符
function back() {
  const str = document.getElementById("text");
  str.value = str.value.substring(0, str.value.length - 1);
}

// 重置显示框
function reset() {
  const str = document.getElementById("text");
  str.value = "";
}

// 将常数 Math.E 插入到显示框
function insertE() {
  const str = document.getElementById("text");
  str.value += Math.E;
}

// 在 getAns 函数中返回 Promise,用于获取答案
function getAns() {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:5000/get', true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          const Data = JSON.parse(xhr.responseText);
          const array = Data["data"];
          console.log(array);
          resolve(array[0][1]);
        } else {
          console.error('获取数据出错: ' + xhr.status);
          reject(xhr.status);
        }
      }
    };
    xhr.send();
  });
}

// 获取历史记录
function getHistory() {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', 'http://localhost:5000/get', true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        Data = JSON.parse(xhr.responseText);
        array = Data["data"];
        console.log(array);
        let string = "";
        for (let i = 0; i < array.length; i++) {
          string += array[i][0] + " = " + array[i][1];
          string += '\n';
        }
      } else {
        console.error('获取数据出错: ' + xhr.status);
      }
    }
  };
  xhr.send();
}

b. HTML

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>Simple Calculator in Web</title>
		<link href="css/PageSetting.css" rel="stylesheet" type="text/css" />
		<script type="text/javascript" src="js/CalculatorFunction.js"></script>
		<!-- <script type="text/javascript" src="js/history.js"></script>  -->
		<!-- <script type="text/javascript" src="js/localServer.js"></script> -->
	</head>
	
	<body>
		<div id="calculator">
			<div id="head"><h3>Simple Calculator in Web</h3></div>
			<div id="show" align="center"><input type="text" id="text" ></div>
			<div id="cuttom">
				<table align="center">
					<tr>
						<td><input type="button" value="e" onclick="display('e')"></td>
						<td><input type="button" value="π" onclick="display('π')"></td>
						
						<td><input type="button" value="(" onclick="display('(')"></td>
						<td><input type="button" value=")" onclick="display(')')"></td>
						
						<td><input type="button" value="^" onclick="display('^')"></td>
						<td><input type="button" value="history" onclick="getHistory()"></td>
					</tr>
					<tr>
						<td><input type="button" value="log" onclick="display('log(')"></td>
						<td><input type="button" value="ln" onclick="display('ln(')"></td>
						<td><input type="button" value="ans" onclick="display('Ans')"></td>
						<td><input type="button" value="asin" onclick="display('asin(')"></td>
						<td colspan="2"><input type="button" value="←" onclick="back()"></td>
					</tr>
					<tr>
						<td><input type="button" value="." onclick="display('.')"></td>
						<td><input type="button" value="0" onclick="display(0)"></td>
						<td><input type="button" value="acos" onclick="display('acos(')"></td>
						<td><input type="button" value="atan" onclick="display('atan(')"></td>
						<td colspan="2"><input type="button" value="c" onclick="reset()"></td>
					</tr>
					<tr>
						<td><input type="button" value="7" onclick="display(7)"></td>
						<td><input type="button" value="8" onclick="display(8)"></td>
						<td><input type="button" value="9" onclick="display(9)"></td>
						<td><input type="button" value="+" onclick="display('+')"></td>
						<td><input type="button" value="-" onclick="display('-')"></td>
						<td><input type="button" value="tan" onclick="display('tan(')"></td>
					</tr>
					<tr>
						<td><input type="button" value="4" onclick="display(4)"></td>
						<td><input type="button" value="5" onclick="display(5)"></td>
						<td><input type="button" value="6" onclick="display(6)"></td>
						<td><input type="button" value="*" onclick="display('*')"></td>
						<td><input type="button" value="/" onclick="display('/')"></td>
						<td><input type="button" value="sin" onclick="display('sin(')"></td>
					</tr>
					<tr>
						<td><input type="button" value="1" onclick="display(1)"></td>
						<td><input type="button" value="2" onclick="display(2)"></td>
						<td><input type="button" value="3" onclick="display(3)"></td>
						<td colspan="2"><input type="button" value="=" onclick="equals()"></td>
						<td><input type="button" value="cos" onclick="display('cos(')"></td>
					</tr>
				</table>
				
			</div>
		</div>
	</body>
</html>

c. Css

body {
    background: #f0f0f0;
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

#calculator {
    width: 600px;
    margin: 50px auto;
    border: 1px solid #ccc;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    background-color: #fff;
    border-radius: 10px; /* 添加圆角 */
    padding: 20px; /* 增加内边距 */
}

#head {
    background-color: #333;
    color: #fff;
    text-align: center;
    padding: 10px 0;
    border-radius: 10px; /* 添加圆角 */
}

#head h3 {
    margin: 0;
    font-size: 24px;
}

#show input {
    width: 100%;
    height: 60px;
    font-size: 30px;
    text-align: right;
    border: 2px solid black;
    padding: 10px;
    outline: none;
    box-sizing: border-box;
    border-radius: 10px; /* 添加圆角边框 */
}

#custom {
    padding: 20px;
}

table {
    width: 100%;
    table-layout: fixed;
    margin-top: 15px; /* 上方间隔 */
    margin-bottom: 15px; /* 下方间隔 */
}

table td {
    width: 25%;
    margin: 10px; /* 左右间隔 */
}

table input {
    width: 100%;
    height: 50px;
    font-size: 20px;
    text-align: center;
    border: none;
    outline: none;
    cursor: pointer;
    background: #f0f0f0;
    border-radius: 10px;
    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); /* 添加阴影效果 */
    transition: transform 0.2s, box-shadow 0.2s; /* 添加过渡效果 */
}



/* 鼠标悬停时应用立体效果和放大效果 */
table input:hover {
    background: #ccc;
    transform: scale(1.1); /* 放大效果 */
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2), 0 0 0 2px #000; /* 增加阴影深度和黑色边框 */
}

 ②Back-end Programming Implementation (Python)

/post API

  • Used to store operation expressions and values.
  • The client can send a POST request to this interface, passing a JSON data including the expression and the result of the calculation.
  • The interface inserts the received data into the database and ensures that the latest 10 records are kept and the excess records are deleted.
  • Return a JSON response, including the message "ok" indicating that the operation was successful, or an error message and status code 500 indicating that the operation failed.
@app.route('/post', methods=['POST'])
def post_history():  # 存储运算表达式和值
    try:
        data = request.get_json()  # 获取POST请求的JSON数据
        expression = data.get('expression')
        result = data.get('result')

        time = datetime.datetime.now()

        # 插入新数据
        data = (time, expression, result)
        insert = "INSERT INTO history (time, expression, result) VALUES (%s, %s, %s)"
        cursor.execute(insert, data)

        # 获取当前记录数量
        cursor.execute("SELECT COUNT(*) FROM history")
        record_count = cursor.fetchone()[0]

        # 如果记录数量超过十条,删除最旧的记录
        if record_count > 10:
            delete_old_records = "DELETE FROM history ORDER BY time LIMIT %s"
            cursor.execute(delete_old_records, (record_count - 10,))

        conn.commit()

        response_message = "ok"
        return jsonify({"message": response_message})

    except Exception as e:
        error_message = str(e)
        return jsonify({"error": error_message}), 500
#用于存储运算表达式和值。
#客户端可以向此接口发送 POST 请求,传递一个 JSON 数据包括表达式和计算结果。
#该接口会将接收到的数据插入数据库中,并确保保留最新的 10 条记录,删除多余的记录。
#返回一个 JSON 响应,包括消息 "ok" 表示操作成功,或者包括错误消息和状态码 500 表示操作失败。

/get API

  • Used to obtain historical operation expressions and results.
  • A client can send a GET request to this interface to get the latest 10 history records.
  • The interface queries the history in the database and returns a JSON response with the expression and result data.
  • If the query fails, an error message and status code 500 are returned.
@app.route('/get', methods=['GET'])
def get_calculation_data():  # 得到历史值
    try:
        cursor.execute("SELECT expression, result FROM history ORDER BY time DESC LIMIT 10")
        data = cursor.fetchall()
        return jsonify({"data": data})

    except Exception as e:
        error_message = str(e)
        return jsonify({"error": error_message}), 500
#用于获取历史运算表达式和结果。
#客户端可以向此接口发送 GET 请求,以获取最新的 10 条历史记录。
#该接口会查询数据库中的历史记录,并返回一个 JSON 响应,其中包括表达式和结果的数据。
#如果查询失败,将返回错误消息和状态码 500。

VII. Project future outlook

Classify users by setting new interactive bars and new calculation logic, so that specific users can directly use the calculation keys related to the intended purpose, such as tax calculation, game equipment damage calculation and other functions.


VIII. Reflections

In this assignment, I successfully completed the development of web from front end to back end, which further improved my understanding of the connection between front and back end, and made the connection process and details clearer. As an EE student, after completing this project, I have also preliminarily mastered the code writing of java script, css and html, and become more familiar with the development framework of web pages, which will be of great help to my further study.


IX. Reference material

...全文
969 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
chennuo. 2023-11-04
  • 打赏
  • 举报
回复

项目设计理念部分,用pycharm写java代码?

-草甸- 2023-11-05
  • 举报
回复
@chennuo. 在网上学的Python flask 里的jsonify,由于是零基础可能有理解不当的地方,不好意思

176

社区成员

发帖
与我相关
我的任务
社区描述
梅努斯软件工程
软件工程 高校 福建省·福州市
社区管理员
  • LinQF39
  • Jcandc
  • chjinhuu
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧