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=[0,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,0,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();

    context.fillText("每日库存变化折线,红点意味着低于安全库存,黄点意味着超储",400,50);

    context.fillText("库存",10,20);
    context.fillText("日期",1200,235);
}

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();

    // 2
    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;
}
//-->
</script>

 

转载于:https://www.cnblogs.com/xiandedanteng/p/7595223.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
软件大小:6.1MB 软件类别:国产软件 / 其它行业 软件授权:破解版 软件语言:简体中文 更新时间: 2011-12-14 《速用进销存软件》是国内唯一图形化的进销存财务软件,以点击录入式的操作,图形化的导航式界面,快速完成日常贸易管理中的进货、货、存货等操作,并结合准确、高效的财务统计和业务分析功能,通过交互式的数据中心与一目了然的统计报表,使企业决策者最关心的进销存往来款项、销售状况、库存数量等能够即点即现。   从软件的模块功能进行划分,速用进销存软件主要分为货品销售管理,材料采购管理,仓库库存管理,财务收支管理,软件权限管理等几大部分:   一、销售管理   销售管理是速用进销存软件的核心管理功能,销售管理以客户管理为对象,通过客户的进销存应收款项,已收款项,客户欠款等数据简单直接地反映企业销售状况,具有销售单据管理,货品单据管理,应收应付帐簿,财务收支记录等管理功能,可记录客户的历史货品成交价格,能通过点击式操作快速开单,自动弹货品价格,能打印各类进销存单据,进销存票据。   二、采购管理   采购管理是速用进销存软件的重要管理功能,采购管理以供应商管理为主,从供应商的货品采购,货款支付,财务收支等方面反映企业的采购状况,具有采购单据管理,货品入仓管理,应收应付帐簿,财务收支记录等管理功能,能统计进货成本,存货数量,能打印各类进销存进货单据,通过速用进销存软件点击式采购开单操作,软件会自动为用户生成货品信息和进货价格。   三、仓库管理   即点即现的仓库管理技术,实时的仓库管理界面,可以随时查看仓库各类货品的库存状况,能够分别管理货品进货、货价格,统计货品的采购成本与销售利润,速用进销存软件的货品库存能够实现完全自动化管理,各类货品的库存都随着采购开单与销售开单实时生成,无需手工录入,并能够进行库存自动报警设置,可为不同的进销存货品设置不同的库存报警数量。   四、财务管理   速用进销存的货品进销存管理与企业财务管理紧密结合,实现真正的进、销、存、财一体化管理效果,清晰准确地记录每一笔财务上的收支,通过多样化的图表,直观生动地反映企业的财务管理数据,并可以形成生动的财务图形化分析图,让企业的财务状况跃然纸上   五、权限管理   速用进销存软件分为多种不同的管理角色,灵活地控制不同管理角色的管理权限,分别使用进销存各部分的管理功能,例如销售人员只要负责进销存中的货管理,客户管理;采购人员主要负责进货管理,仓库管理,库存盘点;而管理员则负责软件数据库的备份与恢复;另外速用软件建议用户,最好能够养成定期进行软件数据库备份的好习惯,未雨绸缪,确保数据万无一失
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值