【Canvas】绘制直方图例子

放一个Canvas绘制直方图的例子在这里,以备日后不时之需。

先上图:

代码:

复制代码
<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>直方图绘制</title>
     <style type="text/css">
     .centerlize{
        margin:0 auto;
        border:0px solid red;
        width:1200px;height:600px;
     }

     </style>
    </head>

     <body onload="draw();">
        <div class="centerlize">
            <canvas id="myCanvas" width="1200px" height="600px" style="border:1px dashed black;">
                出现文字表示您的浏览器尚不支持HTML5 Canvas
            </canvas>
        </div>
     </body>
</html>
<script type="text/javascript">
<!--
// 画布宽度
const WIDTH=1200;

// 画布高度
const HEIGHT=600;

// 中心固定圆半径
const RADIUS=200;


// 画图前初始化
function draw(){
    var canvas=document.getElementById('myCanvas');    
    canvas.width=WIDTH;
    canvas.height=HEIGHT;    

    context=canvas.getContext('2d');   
    
    // 进行屏幕坐标系到笛卡尔坐标系的变换,原点移动到画布中央,右方为X正向,上方为Y的正向
    context.translate(0,HEIGHT-50);
    context.rotate(getRad(180));
    context.scale(-1,1);

    slot=new Slot();
    
    animate();
};

//-------------------------------
// 画图
//-------------------------------
function animate(){    

    let datas=[{text:'勇气',count:80},{text:'毅力',count:120},{text:'果敢',count:450},
              {text:'机敏',count:32},{text:'决心',count:360},{text:'明智',count:230}];
    slot.update(datas);
    slot.paintBg(context);
    slot.paint(context);

}

//-------------------------------
// Slot对象定义处
//-------------------------------
function Slot(){
    var obj=new Object;

    // 画直方图的数据
    obj.datas=[];

    // 传入参数更新内部数据
    obj.update=function(datas){
        this.datas=datas;
    };

    // 画背景
    obj.paintBg=function(ctx){
        // 清屏
        ctx.clearRect(0,-50,WIDTH,HEIGHT);
        
        // 画轴线
        //drawAxisX(ctx,0,WIDTH,100);
       // drawAxisY(ctx,-50,HEIGHT-50,100);
       
        drawText(ctx,"绘制:逆火狂飙",1150,-35);
    };

    // 画前景
    obj.paint=function(ctx){  
        const YMAX=450;
        
        let n=this.datas.length;

        // --往下是竖向网格线
        const stepx=WIDTH/n;
        const CW=stepx/3;// CW:Column Width

        ctx.lineWidth=0.5;
        ctx.strokeStyle='gray';

        for(var i=0;i<n;i++){
            let x=i*stepx;
            let y=YMAX;

            // 恢复实线
            ctx.setLineDash([]);
            ctx.beginPath();
            ctx.moveTo(x, 0);
            ctx.lineTo(x, y);
            ctx.stroke();
            ctx.closePath();

            // 画虚线
            ctx.setLineDash([5,2]);
            ctx.lineDashOffset=1;
            ctx.beginPath();
            ctx.moveTo(x+CW, 0);
            ctx.lineTo(x+CW, y);
            ctx.moveTo(x+2*CW, 0);
            ctx.lineTo(x+2*CW, y);
            ctx.stroke();
            ctx.closePath();
        }

        // --往下是画横向网格线
        const stepy=YMAX/n;
        const GH=stepy/3;// GH:Grid Width

        for(var i=0;i<=n;i++){
            let y=i*stepy;

            // 恢复实线
            ctx.setLineDash([]);
            ctx.beginPath();
            ctx.moveTo(0, y);
            ctx.lineTo(WIDTH, y);
            ctx.stroke();
            ctx.closePath();

            if(i>0){
                // 画虚线
                ctx.setLineDash([5,2]);
                ctx.lineDashOffset=1;
                ctx.beginPath();
                ctx.moveTo(0,y-GH);
                ctx.lineTo(WIDTH, y-GH);
                ctx.moveTo(0,y-2*GH);
                ctx.lineTo(WIDTH, y-2*GH);
                ctx.stroke();
                ctx.closePath();
            }
        }

        // 以最高点定比例
        let maxCnt=-1;
        for(var i=0;i<n;i++){
            var data=this.datas[i];

            if(data.count>maxCnt){
                maxCnt=data.count;
            }
        }
        const ratio=YMAX/maxCnt;

        // --往下是画柱状图
        for(var i=0;i<n;i++){
            var data=this.datas[i];

            var x=i*stepx+(CW);
            var y=0;
            var w=CW;
            var h=data.count*ratio;

            // 阴影设置
            ctx.shadowOffsetX=3;
            ctx.shadowOffsetY=-2;
            ctx.shadowBlur=1;
            ctx.shadowColor='rgba(0,0,0,0.5)';

            // 画柱子
            ctx.fillStyle=getColor(i);
            ctx.fillRect(x,y,w,h);

            // 取消阴影设置
            ctx.shadowOffsetX=0;
            ctx.shadowOffsetY=0;

            // 在柱子顶写文字
            ctx.fillStyle="black";
            drawText(ctx,data.text+"="+data.count,x+CW/2,h+5);
        }

        // 书写标题
        ctx.fillStyle="navy";
        ctx.font="30px 仿宋";
        drawText(ctx,"Canvas绘制直方图例子",WIDTH/2,HEIGHT-100);
    };
    
    return obj;
}
// 连点成线画曲线
function paintCurve(ctx,color,cds){
    var SU=1;// Scale Unit

    ctx.strokeStyle = color;
    ctx.beginPath();        
    for(var i=0; i<cds.length; i++){  
        ctx.lineTo(cds[i].x*SU,cds[i].y*SU);
    }         
    ctx.stroke();
    ctx.closePath();
}
//-----------------------------------------------
// 画横轴
// ctx:画布环境
// startx:起始点横坐标
// endx:结束点横坐标
// step:画刻度的步长,注意画刻度处是步长的整倍数
//-----------------------------------------------
function drawAxisX(ctx,startx,endx,step){
    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='navy';
    ctx.fillStyle='navy';

    // 画轴
    ctx.beginPath();
    ctx.moveTo(startx, 0);
    ctx.lineTo(endx, 0);
    ctx.stroke();
    ctx.closePath();

    // 画箭头
    ctx.beginPath();
    ctx.moveTo(endx-Math.cos(getRad(15))*10, Math.sin(getRad(15))*10);
    ctx.lineTo(endx, 0);
    ctx.lineTo(endx-Math.cos(getRad(15))*10, -Math.sin(getRad(15))*10);
    ctx.stroke();
    ctx.closePath();
    
    // 画刻度
    var x,y;
    y=5;
    for(x=startx;x<endx;x++){
        if((x % step)==0){
            ctx.beginPath();
            ctx.moveTo(x, 0);
            ctx.lineTo(x, y);
            
            ctx.stroke();
            ctx.closePath();

            drawText(ctx,x+"",x,y-20);
        }
    }

    ctx.restore();
}

//-----------------------------------------------
// 画纵轴
// ctx:画布环境
// starty:起始点纵坐标
// endy:结束点纵坐标
// step:画刻度的步长,注意画刻度处是步长的整倍数
//-----------------------------------------------
function drawAxisY(ctx,starty,endy,step){
    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='navy';
    ctx.fillStyle='navy';

    // 画轴
    ctx.beginPath();
    ctx.moveTo(0, starty);
    ctx.lineTo(0, endy);
    ctx.stroke();
    ctx.closePath();

    // 画箭头
    ctx.beginPath();
    ctx.moveTo(Math.sin(getRad(15))*10, endy-Math.cos(getRad(15))*10);
    ctx.lineTo(0, endy);
    ctx.lineTo(-Math.sin(getRad(15))*10, endy-Math.cos(getRad(15))*10);
    ctx.stroke();
    ctx.closePath();
    
    // 画刻度
    var x,y;
    x=5;
    for(y=starty;y<endy;y+=1){
        if((y % step)==0){
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(0, y);
            
            drawText(ctx,y+"",x-15,y);

            ctx.stroke();
            ctx.closePath();
        }
    }
}

//-------------------------------
// 角度得到弧度
//-------------------------------
function getRad(degree){
    return degree/180*Math.PI;
}

//-------------------------------
// 得到颜色
//-------------------------------
function getColor(index){
    var arr=["red","purple","blue","green","skyblue","yellow","#aa0000",
             "orange","maroon","navy",
             "lime","teal","fuchsia",
             "aqua","black"];

    if(index>arr.length){
        index=index % arr.length;
    }

    return arr[index];
}

//-------------------------------
// 在笛卡尔坐标系中绘制文字
//-------------------------------
function drawText(ctx,text,x,y){
    ctx.save();
    ctx.translate(x,y)
    ctx.rotate(getRad(180))
    ctx.scale(-1,1)

    ctx.textBaseline="bottom";
    ctx.textAlign="center";
    ctx.fillText(text,0,0);
    ctx.restore();
}
//-->
</script>
复制代码

END

posted @ 2022-01-15 12:12  不朽的飞翔  阅读(139)  评论(0编辑  收藏  举报