起因
闲来无事,最近正在学习typescript,第一方面深知自身水平不够,想通过编写一些有趣的应用来提高自己,第二方面想测试测试自己到底有没有提升。便编写了这个小demo,编写的过程中遇到了许多的问题。比如移动这个效果就折腾了好久,因为没有看过开源的这种应用是怎么写的,所以从 0 到 1 这个过程很艰难,但好在坚持了下来。 这个demo还有一些功能尚未完善,比如函数表达式的解析,放大缩小等。
ts 代码
interface moveTimes {
vertical: number;
level: number;
}
class DrawFunc {
constructor(
public el: HTMLCanvasElement = document.querySelector("#canvas")!,
public app: CanvasRenderingContext2D = el.getContext("2d")!,
public scale: number = 30,
public line: number = 6,
public offsetX: number = 30,
public offsetY: number = 30,
public fontSize: number = 12,
public w: number = el.width,
public h: number = el.height,
public express: string = "x*x",
public funcStep: number = 0.1,
public moveTimes: moveTimes = {
vertical: 0,
level: 0,
}
) {
this.initAxis(this.w / 2, this.h / 2);
this.drawAll();
this.bindEvent();
}
private drawAll() {
this.drawGrid("#ddd");
this.drawAxis();
this.drawPosition();
this.drawText("green");
this.drawFunction("red");
}
private clear() {
this.app.clearRect(
-this.w / 2 - this.offsetX * this.moveTimes.level,
-this.h / 2 - this.offsetY * this.moveTimes.vertical,
this.w + Math.abs(this.offsetX * this.moveTimes.level),
this.h + Math.abs(this.offsetY * this.moveTimes.vertical)
);
}
private moveEvent(tmpOffsetX: number, tmpOffsetY: number, e: MouseEvent) {
if (tmpOffsetX < e.offsetX) {
this.moveTimes.level--;
this.initAxis(-this.offsetX, 0);
}
if (tmpOffsetX > e.offsetX) {
this.moveTimes.level++;
this.initAxis(this.offsetX, 0);
}
if (tmpOffsetY < e.offsetY) {
this.moveTimes.vertical--;
this.initAxis(0, -this.offsetY)
}
if (tmpOffsetY > e.offsetY) {
this.moveTimes.vertical++;
this.initAxis(0, this.offsetY)
}
this.clear()
this.drawAll()
}
private bindEvent() {
this.el.addEventListener("mousedown", (e) => {
let tmpOffsetX = e.offsetX;
let tmpOffsetY = e.offsetY;
const bindMoveEvent = this.moveEvent.bind(this, tmpOffsetX, tmpOffsetY)
this.el.addEventListener(
"mousemove",
bindMoveEvent
);
this.el.addEventListener("mouseup", () => {
this.el.removeEventListener(
"mousemove",
bindMoveEvent
);
});
});
document.querySelector("#moveRight")!.addEventListener("click", () => {
this.clear();
this.moveTimes.level--;
this.initAxis(-this.offsetX, 0);
});
document.querySelector("#moveLeft")!.addEventListener("click", () => {
this.clear();
this.moveTimes.level++;
this.initAxis(this.offsetX, 0);
});
document.querySelector("#moveUp")!.addEventListener("click", () => {
this.clear();
this.moveTimes.vertical++;
this.initAxis(0, this.offsetY);
});
document.querySelector("#moveDown")!.addEventListener("click", () => {
this.clear();
this.moveTimes.vertical--;
this.initAxis(0, -this.offsetY);
});
document.querySelector("#moveButton")!.addEventListener("click", () => {
this.drawAll();
});
}
private initAxis(offsetX: number, offsetY: number) {
this.app.translate(offsetX, offsetY);
}
private drawFunction(color: string) {
let x;
this.app.save();
this.app.strokeStyle = color;
this.app.beginPath();
x = (-this.w / 2 - this.offsetX * this.moveTimes.level) / this.scale;
while (
x <=
(this.w / 2 - this.offsetX * this.moveTimes.level) / this.scale
) {
this.app.moveTo(x * this.scale, -eval(this.express) * this.scale);
x += this.funcStep;
this.app.lineTo(x * this.scale, -eval(this.express) * this.scale);
this.app.stroke();
}
this.app.closePath();
this.app.restore();
}
private drawText(color: string) {
let x, y;
let text;
this.app.save();
this.app.beginPath();
this.app.fillStyle = color;
this.app.font = `${this.fontSize}px serif`;
y = this.scale;
text = -1;
while (y <= this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.fillText(`${text}`, this.fontSize / 2, y);
y += this.scale;
text--;
}
text = 1;
y = -this.scale + this.fontSize / 2;
while (y >= -this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.fillText(`+${text}`, this.fontSize / 2, y);
y -= this.scale;
text++;
}
text = -1;
x = -this.scale;
while (x >= -this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.fillText(`${text}`, x, this.fontSize);
x -= this.scale;
text--;
}
text = 1;
x = this.scale - this.fontSize;
while (x <= this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.fillText(`+${text}`, x, this.fontSize);
x += this.scale;
text++;
}
this.app.closePath();
this.app.restore();
}
private drawPosition() {
let x, y;
this.app.beginPath();
y = this.scale;
while (y <= this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.moveTo(-this.line / 2, y);
this.app.lineTo(this.line / 2, y);
this.app.stroke();
y += this.scale;
}
y = -this.scale;
while (y >= -this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.moveTo(-this.line / 2, y);
this.app.lineTo(this.line / 2, y);
this.app.stroke();
y -= this.scale;
}
x = this.scale;
while (x <= this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.moveTo(x, -this.line / 2);
this.app.lineTo(x, this.line / 2);
this.app.stroke();
x += this.scale;
}
x = -this.scale;
while (x >= -this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.moveTo(x, -this.line / 2);
this.app.lineTo(x, this.line / 2);
this.app.stroke();
x -= this.scale;
}
this.app.closePath();
}
private drawGrid(color: string) {
let x, y;
this.app.save();
this.app.lineWidth = 1;
this.app.strokeStyle = color;
this.app.beginPath();
y = this.scale;
while (y <= this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.moveTo(-this.w / 2 - this.offsetX * this.moveTimes.level, y);
this.app.lineTo(this.w / 2 - this.offsetX * this.moveTimes.level, y);
this.app.stroke();
y += this.scale;
}
y = -this.scale;
while (y >= -this.h / 2 - this.offsetY * this.moveTimes.vertical) {
this.app.moveTo(-this.w / 2 - this.offsetX * this.moveTimes.level, y);
this.app.lineTo(this.w / 2 - this.offsetX * this.moveTimes.level, y);
this.app.stroke();
y -= this.scale;
}
x = this.scale;
while (x <= this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.moveTo(x, -this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.lineTo(x, this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.stroke();
x += this.scale;
}
x = -this.scale;
while (x >= -this.w / 2 - this.offsetX * this.moveTimes.level) {
this.app.moveTo(x, -this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.lineTo(x, this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.stroke();
x -= this.scale;
}
this.app.closePath();
this.app.restore();
}
private drawAxis() {
this.app.beginPath();
this.app.moveTo(-this.w / 2 - this.offsetX * this.moveTimes.level, 0);
this.app.lineTo(this.w / 2 - this.offsetX * this.moveTimes.level, 0);
this.app.moveTo(0, -this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.lineTo(0, this.h / 2 - this.offsetY * this.moveTimes.vertical);
this.app.stroke();
this.app.closePath();
}
}
let draw = new DrawFunc();
测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数画图 Demo</title>
<style>
#canvas {
border: solid 5px #ddd;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
}
#moveButton {
display: flex;
width: 500px;
align-items: center;
height: 40px;
background: #34495e;
border: solid 5px #ddd;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
}
#moveButton div {
cursor: pointer;
flex: 1;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<div id="moveButton">
<div id="moveRight">右移</div>
<div id="moveLeft">左移</div>
<div id="moveUp">上移</div>
<div id="moveDown">下移</div>
</div>
<script src="index.js"></script>
</body>
</html>
效果
南无阿弥陀佛,南无药王菩萨
|