• Canvas入门08-绘制仪表盘


    需求

    实现下图所示的仪表盘的绘制。

    分析

    我们先来将仪表盘进行图形拆分,并定义尺寸。

    我们绘制的逻辑:

    1. 绘制中心圆
    2. 绘制环外圈圆
    3. 绘制环内圈圆
    4. 绘制刻度内圈圆
    5. 绘制刻度线
    6. 绘制刻度文字
    7. 绘制指针

    定义圆

    var circle = {
        x: canvas.width / 2,
        y: canvas.height / 2,
        radius: 150
    };
    

    绘制中心圆

    中心圆半径是10,圆心是画布中心。

    const CENTROID_RADIUS = 10;
    const CENTROID_STROKE_STYLE = 'rgba(0,0,0,.5)';
    const CENTROID_FILL_STYLE = 'rgba(80,190,240,.6)';
    
    // 画仪表盘中心
    function drawCentroid() {
        context.beginPath();
        context.save();
        context.strokeStyle = CENTROID_STROKE_STYLE;
        context.fillStyoe = CENTROID_FILL_STYLE;
        context.arc(circle.x, circle.y, CENTROID_RADIUS, 0, 2 * Math.PI, false);
        context.stroke();
        context.fill();
        context.restore();
    }
    

    绘制环

    这里应用了剪纸效果技巧,环外圈圆顺时针绘制,环内圈圆逆时针顺时针绘制,需要注意方向。

    
    const RING_INNER_RADIUS = 35;
    const RING_OUTER_RADIUS = 55;
    
    // 绘制环外圈圆
    function drawRingOuterCircle() {
        context.shadowColor = 'rgba(0,0,0,.7)';
        context.shadowOffsetX = 3;
        context.shadowOffsetY = 3;
        context.shadowBlur = 6;
        context.strokeStyle = TRACKING_DIAL_STROKING_STYLE;
        context.beginPath();
        context.arc(circle.x, circle.y, circle.radius + RING_OUTER_RADIUS, 0, 2 * Math.PI, true);
        context.stroke();
    
    }
    
    
    // 绘制环外圈圆
    function drawRingInnerCircle() {
        context.strokeStyle = 'rgba(0,0,0,.1)';
        context.arc(circle.x, circle.y, circle.radius + RING_INNER_RADIUS, 0, 2 * Math.PI, false);
        context.fillStyle = 'rgba(100,140,230,.1)';
        context.fill();
        context.stroke();
    }
    
    

    绘制效果:

    绘制刻度内圈圆

    const TICK_WIDTH = 10;
    
    // 绘制刻度内圆
    function drawTickInnerCircle() {
        context.save();
        context.beginPath();
        context.strokeStyle = 'rgba(0,0,0,.1)';
        context.arc(circle.x, circle.y, circle.radius + RING_INNER_RADIUS - TICK_WIDTH, 0, 2 * Math.PI, false);
        context.stroke();
        context.restore();
    }
    

    绘制效果:

    绘制刻度线

    每条刻度线,其实是一个短线段,需要确定Line的起始坐标和终止坐标。

    const TICK_WIDTH = 10;
    
    // 绘制刻度
    function drawTicks() {
        var radius = circle.radius + RING_INNER_RADIUS;
        var ANGLE_MAX = 2 * Math.PI;
        // var ANGLE_DELTA = Math.PI / 64;
        var ANGLE_DELTA = Math.PI / 24;
    
        var tickWidth;
    
        context.save();
    
        for (var angle = 0, count = 0; angle < ANGLE_MAX; angle += ANGLE_DELTA, count+=15) {
            drawTick(angle, radius, count);
        }
        context.restore();
    }
    
    function drawTick(angle, radius, count) {
        var tickWidth = count % 15 === 0 ? TICK_WIDTH : TICK_WIDTH / 2;
    
        context.beginPath();
        context.moveTo(circle.x + (radius - tickWidth) * Math.cos(angle), circle.y + (radius - tickWidth) * Math.sin(angle));
        context.lineTo(circle.x + (radius) * Math.cos(angle), circle.y + (radius) * Math.sin(angle));
        context.strokeStyle = TICK_SHORT_STROKE_STYLE;
        context.stroke();
    
    }
    
    

    绘制刻度值

    注意刻度值是每个2个刻度线,绘制一个text。

    const ANNOTATIONS_FILL_STYLE = 'rgba(0,0,230,.9)';
    const ANNOTATIONS_TEXT_SIZE = 12;
    
    function drawAnnotations() {
        var radius = circle.radius + RING_INNER_RADIUS;
        // var deltaAngle = Math.PI /8;
        var deltaAngle = Math.PI / 12;
        context.save();
        context.fillStyle = ANNOTATIONS_FILL_STYLE;
        context.font = ANNOTATIONS_TEXT_SIZE + 'px Helvetica';
    
        for (var angle = 0; angle < 2 * Math.PI; angle += deltaAngle) {
            context.beginPath();
            var degree = (angle * 180 / Math.PI).toFixed(0);
            var pt = {
                x: circle.x + (radius - TICK_WIDTH * 2) * Math.cos(angle),
                y: circle.x - (radius - TICK_WIDTH * 2) * Math.sin(angle)
            }
            if (degree !== '360') {
                context.fillText(degree, pt.x, pt.y);
            }
        }
    
        context.restore();
    }
    
    

    效果:

    绘制指针

    这里没有动画,所以给的是固定角度。

    
    // 绘制指针
    function drawCentroidGuidewire(loc) {
        var angle = -Math.PI / 4;
        var radius = circle.radius + RING_OUTER_RADIUS;
        var endpt;
    
        if (loc.x > circle.x) {
            endpt = {
                x: circle.x + radius * Math.cos(angle),
                y: circle.y + radius * Math.sin(angle)
            };
        } else {
            endpt = {
                x: circle.x - radius * Math.cos(angle),
                y: circle.y - radius * Math.sin(angle)
            };
        }
    
        context.save();
    
        context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
        context.fillStyle = GUIDEWIRE_FILL_STYLE;
    
        context.beginPath();
        context.moveTo(circle.x, circle.y);
        context.lineTo(endpt.x, endpt.y);
        context.stroke();
    
        context.beginPath();
        context.strokeStyle = TICK_LONG_STROKE_STYLE;
        context.arc(endpt.x, endpt.y, 5, 0, 2 * Math.PI, false);
        context.fill();
        context.stroke();
    
        context.restore();
    }
    
    

    最后调用的时候,先绘制指针,再绘制中心点,这样可以使指针在中心点下层,好看一些。

    function drawDial() {
        var loc = { x: circle.x, y: circle.y };
    
    
        drawCentroidGuidewire(loc);
        drawCentroid();
        drawRingOuterCircle();
        drawRingInnerCircle();
        drawTickInnerCircle();
        drawTicks();
        drawAnnotations();
    }
    
    
    // Initialization 
    context.shadowColor = 'rgba(0,0,0,.4)';
    context.shadowOffsetX = 2;
    context.shadowOffsetY = 2;
    context.shadowBlur = 4;
    
    context.textAlign = 'center';
    context.textBaseline = 'middle';
    
    drawDial();
    
    
    
  • 相关阅读:
    爬虫——网页解析利器--re & xpath
    机器学习——决策树
    爬虫——控制台抓包和requests.post()发送请求
    爬虫——爬取Ajax动态加载网页
    爬虫——urllib爬虫模块
    从零搭建一个SpringCloud项目之Zuul(四)
    从零搭建一个SpringCloud项目之hystrix(三)
    从零搭建一个SpringCloud项目之Eureka(一)
    SpringBoot内置Tomcat启动的源码分析
    初始化Bean的扩展InitializingBean和BeanPostProcessor
  • 原文地址:https://www.cnblogs.com/liulei-cherry/p/9952829.html
Copyright © 2020-2023  润新知