带数字标签的坐标轴的绘制

简介: 带数字标签的坐标轴的绘制

<!DOCTYPE html>
<!--
    Author:苏一恒
    Date:2019/10/23 09:08
    Motto:
        The best time to plant trees is ten years ago, followed by now. 
        种树最好的时间是十年前,其次是现在。
 -->
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>带数字标签的坐标轴的绘制</title>
</head>
<body>
<canvas id="canvas" width="400" height="300"></canvas>
</body>
<script>
    let canvas = document.getElementById('canvas'),
        context = canvas.getContext('2d'),
 
        //外边距
        AXIS_MARGIN = 40,
        //原点,将之设置到画布左下区域
        AXIS_ORIGIN = {x: AXIS_MARGIN, y: canvas.height - AXIS_MARGIN},
 
        //y轴顶点位置
        AXIS_TOP = AXIS_MARGIN,
        //x轴顶点位置
        AXIS_RIGHT = canvas.width - AXIS_MARGIN,
 
        //横向刻度线间距
        HORIZONTAL_TICK_SPACING = 10,
        //垂直刻度线间距
        VERTICAL_TICK_SPACING = 10,
 
        //X轴长度
        AXIS_WIDTH = AXIS_RIGHT - AXIS_ORIGIN.x,
        //y轴长度
        AXIS_HEIGHT = AXIS_ORIGIN.y - AXIS_TOP,
 
        //y轴上的点的最大值
        NUM_VERTICAL_TICKS = AXIS_HEIGHT / VERTICAL_TICK_SPACING,
        NUM_HORIZONTAL_TICKS = AXIS_WIDTH / HORIZONTAL_TICK_SPACING,
 
        TICK_WIDTH = 10,
        TICKS_LINEWIDTH = 0.5,
        TICK_COLOR = 'navy',
 
        AXIS_LINEWIDTH = 1.0,
        AXIS_COLOR = 'blue';
 
        //数字与坐标轴的距离
        SPACE_BETWEEN_LABELS_AND_AXIS =  15;
 
 
    //Function……
 
    /**
     * 背景网格线
     * @param color
     * @param stepX
     * @param stepY
     */
    let drawGrid=(color, stepX, stepY)=> {
        context.strokeStyle = color;
        context.lineWidth = 0.5;
 
        for (let i = stepX + 0.5; i < context.canvas.width; i += stepX) {
            context.beginPath();
            context.moveTo(i, 0);
            context.lineTo(i, context.canvas.height);
            context.stroke();
        }
 
        for (let i = stepY + 0.5; i < context.canvas.height; i += stepY) {
            context.beginPath();
            context.moveTo(0, i);
            context.lineTo(context.canvas.width, i);
            context.stroke();
        }
    };
 
    /**
     * 画坐标轴
     */
    let drawAxis=() =>{
        context.save();
        context.strokeStyle = AXIS_COLOR;
        context.lineWidth = AXIS_LINEWIDTH;
 
        drawHorizontalAxis();
        drawVerticalAxis();
 
        context.lineWidth = TICKS_LINEWIDTH;
        context.strokeStyle = TICK_COLOR;
 
        drawVerticalAxisTicks();
        drawHorizontalAxisTicks();
 
        context.restore();
    };
 
    /**
     * 绘制x轴
     */
    let drawHorizontalAxis=()=> {
        context.beginPath();
        context.moveTo(AXIS_ORIGIN.x, AXIS_ORIGIN.y);
        context.lineTo(AXIS_RIGHT, AXIS_ORIGIN.y);
        context.stroke();
    };
 
 
    /**
     * 绘制y轴
     */
    let drawVerticalAxis=()=> {
        context.beginPath();
        context.moveTo(AXIS_ORIGIN.x, AXIS_ORIGIN.y);
        context.lineTo(AXIS_ORIGIN.x, AXIS_TOP);
        context.stroke();
    };
 
    /**
     * 绘制y轴刻度
     */
    let drawVerticalAxisTicks=()=> {
        //小刻度长度的临时变量
        let deltaY;
 
        for (let i = 1; i < NUM_VERTICAL_TICKS; i++) {
            context.beginPath();
            //每5第五个刻度为长的小刻度
            deltaY = i % 5 === 0 ? TICK_WIDTH : TICK_WIDTH / 2;
            context.moveTo(AXIS_ORIGIN.x - deltaY, AXIS_ORIGIN.y - i * VERTICAL_TICK_SPACING);
            context.lineTo(AXIS_ORIGIN.x + deltaY, AXIS_ORIGIN.y - i * VERTICAL_TICK_SPACING);
            context.stroke();
 
        }
    };
 
    /**
     * 绘制x轴刻度
     */
    let drawHorizontalAxisTicks=()=> {
        //小刻度长度的临时变量
        let deltaY;
 
        for (let i = 1; i < NUM_HORIZONTAL_TICKS; i++) {
            context.beginPath();
            //每5第五个刻度为长的小刻度
            deltaY = i % 5 === 0 ? TICK_WIDTH : TICK_WIDTH / 2;
 
            context.moveTo(AXIS_ORIGIN.x+i*HORIZONTAL_TICK_SPACING, AXIS_ORIGIN.y-deltaY);
            context.lineTo(AXIS_ORIGIN.x+i*HORIZONTAL_TICK_SPACING, AXIS_ORIGIN.y+deltaY);
            context.stroke();
 
        }
    };
 
    /**
     * 添加坐标轴数字标签
     */
    let drawAxisLabels=()=> {
        context.fillStyle = 'blue';
        drawHorizontalAxisLabels();
        drawVerticalAxisLabels();
    };
 
    /**
     * 添加横坐标数字标签
     */
    let drawHorizontalAxisLabels=()=> {
        context.textAlign = 'center';
        context.textBaseline = 'top';
 
        for (let i=0; i <= NUM_HORIZONTAL_TICKS; ++i) {
            if (i % 5 === 0) {
                context.fillText(i,
                    AXIS_ORIGIN.x + i * HORIZONTAL_TICK_SPACING,
                    AXIS_ORIGIN.y + SPACE_BETWEEN_LABELS_AND_AXIS);
            }
        }
    };
 
    /**
     * 添加垂直坐标数字标签
     */
    let drawVerticalAxisLabels=()=> {
        context.textAlign = 'right';
        context.textBaseline = 'middle';
 
        for (let i=0; i <= NUM_VERTICAL_TICKS; ++i) {
            if (i % 5 === 0) {
                context.fillText(i,
                    AXIS_ORIGIN.x - SPACE_BETWEEN_LABELS_AND_AXIS,
                    AXIS_ORIGIN.y - i * VERTICAL_TICK_SPACING);
            }
        }
    };
    //Initialization……
    drawGrid('lightgray', 10, 10);
    drawAxis();
    drawAxisLabels();
 
 
</script>
</html>
相关文章
|
前端开发 JavaScript 安全
前端JS加密对抗由浅入深-1
本文主要讲解,针对前端加密数据传输站点,如何进行动态调试以获取加密算法、秘钥,本次实验不涉及漏洞挖掘,仅为学习演示,环境为本地搭建环境
基于宜搭的“企业报销流程”实践案例
报销是一个企业的典型场景,本案例着重讲述一个典型的财务报销流程的搭建,已介绍宜搭流程相关的核心功能。报销由员工发起申请,填写报销项以及对应的详情信息,发起审批流程。审批流程计划设置为:当前提交人主管,审批人所在部门对应的财务接口人,财务总监(如果金额大于10000元,则需要加入该角色)
基于宜搭的“企业报销流程”实践案例
|
4月前
|
机器学习/深度学习 人工智能 算法
AI用户标签系统的开发
本项目构建AI驱动的闭环用户标签系统,涵盖数据接入治理、OneID统一识别、特征工程、多算法标签建模(分类/聚类/NLP/时序预测)、离线+实时计算引擎、标签质量评估及API服务层,实现精准、动态、可落地的用户画像。
|
关系型数据库 MySQL Java
实时计算 Flink版操作报错之遇到java.lang.IllegalStateException: The elasticsearch emitter must be serializable.的错误,如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
人工智能 数据可视化 JavaScript
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
NodeTool 是一个开源的 AI 工作流可视化构建器,通过拖放节点的方式设计复杂的工作流,无需编码即可快速原型设计和测试。它支持本地 GPU 运行 AI 模型,并与 Hugging Face、OpenAI 等平台集成,提供模型访问能力。
1065 14
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
|
SQL 数据处理 数据库
如何理解SQL中的自连接?
说起自连接,想必小伙伴们都听说过。在进行数据处理时经常会使用到自连接,特别是像一些连续性的问题中使用的比较多。
如何理解SQL中的自连接?
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
252 0
|
存储 安全 Unix
基于文件系统的ACL
【8月更文挑战第13天】
440 1
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的设计系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的设计系统的详细设计和实现
354 2
|
存储 资源调度 JavaScript
package.json——从vue的package.json来详细说明package.json内容
package.json——从vue的package.json来详细说明package.json内容
512 0