HTML5 Canvas 绘制库存变化折线 画入库出库柱状图

简介:

代码:

复制代码
<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>显示入库出库柱状图</title>
    </head>

     <body onload="draw()">
        <canvas id="myCanvus" width="1240px" height="240px" style="border:1px dashed black;">
            出现文字表示你的浏览器不支持HTML5
        </canvas>
     </body>
</html>
<script type="text/javascript">
<!--
function draw(){
    var canvas=document.getElementById("myCanvus");
    var canvasWidth=1240;
    var canvasHeight=240;

    var context=canvas.getContext("2d");
    
    context.fillStyle = "white";
    context.fillRect(0, 0, canvasWidth, canvasHeight);

    context.strokeStyle = "black";
    context.fillStyle = "black";

    context.save();
    
    // 进行坐标变换:把原点放在左下角,东方为X轴正向,北方为Y轴正向
    var offset=20;// 偏移值,用来画坐标轴

    context.save();
    context.translate(0+offset,canvasHeight-offset);
    context.rotate(getRad(180));
    context.scale(-1,1);        

    drawAxisX(context,canvasWidth-40);
    drawAxisY(context);
    
    // 出库数据,这是主动数据
    var outbounds=[10,70,0,70,0,60,0,60,0,70,0,70,0,70,0,70,0,70,0,70,0,70,0,70,];
    var daysales=0;// 日销售量
    var sum=0;

    // 日销售量=出库数据均值
    for(var i=0;i<outbounds.length;i++){
        sum+=outbounds[i];
    }
    daysales=sum/outbounds.length;
    console.log("日销售量="+daysales);

    // 零件对象,固有属性数据
    var piece=new Object();
    piece.actualStock=100;// 当前实际库存量,单位个
    piece.leadtime=1;// 到货天数,单位天
    piece.safeday=0.5;// 安全系数,单位天
    piece.supplyGap=2;//供应间隔日数,单位天
    piece.reorganizeDay=2;//整理准备日数,单位天

    // 最低库存量
    var minStorage=daysales*(piece.leadtime+piece.safeday);
    console.log("最低库存量="+minStorage);

    // 最高库存量
    var maxStorage=daysales*(piece.supplyGap+piece.reorganizeDay+piece.safeday);
    console.log("最高库存量="+maxStorage);

    // 入库数据,这是被动数据
    var inbounds=[50,0,50,0,50,0,50,20,50,0,90,0,90,0,90,0,90,0,40,0,60,0,70,0,];
    

    drawStockCurve(context,piece.actualStock,inbounds,outbounds,minStorage,maxStorage);
    drawBounds(context,minStorage,maxStorage,canvasWidth-40);

    context.restore();

    

    // 计算库存周转率
    var outTotal=0;// 出库总金额

    // 出库总金额=出库量累计
    for(var i=0;i<outbounds.length;i++){
        outTotal+=outbounds[i];
    }
    console.log("出库总金额="+outTotal);

    // 总库存金额
    var inStock=piece.actualStock;
    sum=0;
    for(var i=0;i<inbounds.length;i++){
        inStock=inStock+inbounds[i]-outbounds[i];
        sum+=inStock;
    }
    console.log("inStock="+inStock);

    var inAvg=sum/inbounds.length;// 平均库存量/平均库存金额
    console.log("平均库存金额="+inAvg);

    var storageRate=outTotal/inAvg*100;
    console.log("库存周转率="+storageRate);
    
    context.fillText("库存周转率="+toCurrency(""+storageRate+"")+"%",1000,40);

    context.fillText("库存",10,20);
    context.fillText("日期",1200,235);
    
    context.font="bold 18px 楷体";
    context.fillStyle="blue";
    context.fillText("每日库存变化折线,红点意味着低于安全库存,黄点意味着超储,紫红色条表示入库,绿色条表示出库",100,30);
}

function drawBounds(ctx,minStorage,maxStorage,axisLength){
    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='red';

    // 画underage
    ctx.beginPath();
    ctx.moveTo(0, minStorage);
    ctx.lineTo(axisLength, minStorage);
    ctx.stroke();
    ctx.closePath();

    ctx.save();
    ctx.translate(-10,minStorage);
    ctx.rotate(getRad(180));
    ctx.scale(-1,1);
    ctx.fillText("告罄",0,0);
    ctx.restore();

    ctx.restore();


    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='red';

    // 画underage
    ctx.beginPath();
    ctx.moveTo(0, maxStorage);
    ctx.lineTo(axisLength, maxStorage);
    ctx.stroke();
    ctx.closePath();

    ctx.save();
    ctx.translate(-10,maxStorage);
    ctx.rotate(getRad(180));
    ctx.scale(-1,1);
    ctx.fillText("超储",0,0);
    ctx.restore();

    ctx.restore();
}

function drawStockCurve(ctx,actualStock,inbounds,outbounds,minStorage,maxStorage){
    ctx.save();
    
    ctx.lineWidth=1;
    ctx.strokeStyle='black';
    ctx.fillStyle='black';

    // 显示折线图
    var y=actualStock;
    var x;

    ctx.beginPath();
    for(var i=0;i<inbounds.length;i++){
        y=y+inbounds[i]-outbounds[i];
        x=i*50;
        ctx.lineTo(x, y);

        ctx.save();
        // 因坐标变换会导致文字错位,故采用位移+旋转+缩放的方式恢复
        ctx.translate(x,y);
        ctx.rotate(getRad(180));
        ctx.scale(-1,1);
        ctx.fillText("("+i+","+y+")",0,0);
        ctx.restore();
    }
    ctx.stroke();
    ctx.closePath();
    
    // 显示当日出库入库柱状图
    y=actualStock;
    x=0;
    var barWidth=5;

    for(var i=0;i<inbounds.length;i++){
        y=inbounds[i];
        x=i*50;

        ctx.fillStyle = "fuchsia";
        ctx.fillRect(x-barWidth, 0, barWidth, y);
        
        y=outbounds[i];
        x=i*50;
        
        ctx.fillStyle = "green";
        ctx.fillRect(x, 0, barWidth, y);
    }
    

    // 显示超储、告罄标志
    y=actualStock;
    x=0;

    for(var i=0;i<inbounds.length;i++){
        y=y+inbounds[i]-outbounds[i];
        x=i*50;
        ctx.lineTo(x, y);

        if(y>maxStorage){
            ctx.beginPath();
            ctx.strokeStyle='yellow';
            ctx.arc(x,y,5,0,Math.PI*2,false);
            ctx.stroke();
            ctx.closePath();
        }

        if(y<minStorage){
            ctx.beginPath();
            ctx.strokeStyle='red';
            ctx.arc(x,y,3,0,Math.PI*2,false);
            ctx.stroke();
            ctx.closePath();
        }
    }

    ctx.restore();
}

function drawAxisX(ctx,axisLength){
    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='navy';
    ctx.fillStyle='navy';

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

    ctx.beginPath();
    ctx.moveTo(axisLength-Math.cos(getRad(15))*10, Math.sin(getRad(15))*10);
    ctx.lineTo(axisLength, 0);
    ctx.lineTo(axisLength-Math.cos(getRad(15))*10, -Math.sin(getRad(15))*10);
    ctx.stroke();
    ctx.closePath();
    
    // 画刻度
    var x,y;
    y=5;
    for(x=50;x<axisLength;x+=50){
        ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, y);
        
        ctx.stroke();
        ctx.closePath();
    }

    // 写文字
    var i=0;
    for(x=0;x<axisLength;x+=50){
        ctx.save();
        ctx.scale(1,-1);
        ctx.fillText(i,x,y+10);
        ctx.restore();

        i++;
    }

    ctx.restore();
}

function drawAxisY(ctx){
    ctx.save();
    
    ctx.lineWidth=0.5;
    ctx.strokeStyle='navy';
    ctx.fillStyle='navy';

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

    ctx.beginPath();
    ctx.moveTo(Math.sin(getRad(15))*10, 200-Math.cos(getRad(15))*10);
    ctx.lineTo(0, 200);
    ctx.lineTo(-Math.sin(getRad(15))*10, 200-Math.cos(getRad(15))*10);
    ctx.stroke();
    ctx.closePath();
    
    // 画刻度
    var x,y;
    x=5;
    for(y=50;y<200;y+=50){
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(0, y);
        
        ctx.stroke();
        ctx.closePath();
    }

    // 写文字
    x=-19;
    for(y=50;y<200;y+=50){
        ctx.save();
        
        ctx.scale(1,-1);
        ctx.translate(0,-200);

        ctx.fillText(200-y,x,y);
        ctx.restore();
    }

    ctx.restore();
}

function getRad(degree){
    return degree/180*Math.PI;
}

function toCurrency(money) {  
    if (/[^0-9\.]/.test(money)){
        return '0.00';
    }

    money = money.replace(/^(\d*)$/, "$1.");
    money = (money + "00").replace(/(\d*\.\d\d)\d*/, "$1");
    money = money.replace(".", ",");
    var re = /(\d)(\d{3},)/;
    while (re.test(money)) {
        money = money.replace(re, "$1,$2");
    }
    money = money.replace(/,(\d\d)$/, ".$1");

    return '' + money.replace(/^\./, "0.")+" ";
} 
//-->
</script>
复制代码

 

















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/xiandedanteng/p/7596156.html,如需转载请自行联系原作者

相关文章
|
12天前
|
前端开发 JavaScript API
2024 新年HTML5+Canvas制作3D烟花特效(附源码)
2024 新年HTML5+Canvas制作3D烟花特效(附源码)
64 0
|
12天前
|
存储 移动开发 前端开发
HTML新特性【HTML5内联SVG、SVG_矩形、SVG 与 Canvas两者间的区别 、HTML5_MathML 】(三)-全面详解(学习总结---从入门到深化)
HTML新特性【HTML5内联SVG、SVG_矩形、SVG 与 Canvas两者间的区别 、HTML5_MathML 】(三)-全面详解(学习总结---从入门到深化)
52 0
|
12天前
|
移动开发 前端开发 API
HTML5 Canvas 提供丰富的绘图API,支持绘制图形、文本、渐变和图像,助力游戏开发
【5月更文挑战第13天】HTML5 Canvas 提供丰富的绘图API,支持绘制图形、文本、渐变和图像,助力游戏开发。关键功能包括绘制基本形状、文本渲染、图像处理及渐变图案。在游戏开发中,Canvas用于绘制游戏元素、实现动画效果、精确的物理碰撞检测,并具有跨平台兼容性,为创造多样化视觉体验和互动游戏提供强大工具。随着技术进步,Canvas在游戏领域的应用将持续增长。
21 4
|
12天前
|
移动开发 前端开发 HTML5
HTML5 Canvas发光Loading源码
一款基于HTML5 Canvas的发光Loading加载HTML源码。Loading旋转图标是在canvas画布上绘制的,整个loading动画是发光3D的视觉效果
17 1
HTML5 Canvas发光Loading源码
|
12天前
|
移动开发 JSON 前端开发
HTML5作业(四)-----饼状图和柱状图绘制【附源码】
该实验旨在熟悉HTML5 Canvas绘制图形和表单交互。用户需输入统计数据,程序将依据数据绘制饼状图和柱状图。要求验证用户输入有效性,点击按钮可切换图表类型,图上需显示数据标注。提供的代码包含一个表单用于输入JSON数据,两个绘制函数(drawPieChart、drawBarChart)用于生成饼状图和柱状图,以及输入验证和颜色生成辅助函数。
|
12天前
|
移动开发 前端开发 HTML5
Canvas实现超酷Loading动画HTML代码
之前我们分享过很多基于CSS3的Loading动画效果,相信大家都很喜欢。今天我们要来分享一款基于HTML5 Canvas的发光Loading加载动画特效。Loading旋转图标是在canvas画布上绘制的,整个loading动画是发光3D的视觉效果,HTML5非常强大。
15 1
Canvas实现超酷Loading动画HTML代码
|
12天前
|
移动开发 前端开发 API
简述HTML5 Canvas的基本绘图API及其在游戏开发中的作用。
HTML5 Canvas 提供丰富的绘图API,用于在网页上绘制图形、动画和视觉效果,支持基本形状、文本、渐变、图像及像素操作。在游戏开发中,Canvas API用于绘制游戏元素、实现动画效果、进行物理碰撞检测,并具备跨平台兼容性,为创新游戏体验提供强有力的支持。
14 1
|
12天前
|
前端开发 JavaScript 容器
编程笔记 html5&css&js 032 HTML Canvas
编程笔记 html5&css&js 032 HTML Canvas
|
12天前
|
移动开发 前端开发 JavaScript
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
135 0
html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形
|
12天前
|
存储 移动开发 前端开发
HTML新特性【HTML5内联SVG、SVG_矩形、SVG 与 Canvas两者间的区别 、HTML5_MathML 】(三)-全面详解(学习总结---从入门到深化)(下)
HTML新特性【HTML5内联SVG、SVG_矩形、SVG 与 Canvas两者间的区别 、HTML5_MathML 】(三)-全面详解(学习总结---从入门到深化)
33 0