IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> canvas函数作图demo -> 正文阅读

[JavaScript知识库]canvas函数作图demo

起因

闲来无事,最近正在学习typescript,第一方面深知自身水平不够,想通过编写一些有趣的应用来提高自己,第二方面想测试测试自己到底有没有提升。便编写了这个小demo,编写的过程中遇到了许多的问题。比如移动这个效果就折腾了好久,因为没有看过开源的这种应用是怎么写的,所以从 0 到 1 这个过程很艰难,但好在坚持了下来。
这个demo还有一些功能尚未完善,比如函数表达式的解析,放大缩小等。

ts 代码

/** 2022/3/12
 * @description 函数作图测试
 * @author twoDay
 * @version 0.0.1
 */

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,     // canvas 的宽度简写
    public h: number = el.height,    // canvas 的高度简写
    public express: string = "x*x",  // 函数表达式
    public funcStep: number = 0.1,   // 例如 y = x*x 中 x 的步长,步长越小越精确
    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>

效果

函数生成器测试
南无阿弥陀佛南无药王菩萨

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 21:41:13  更:2022-03-13 21:43:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:54:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码