html5 canvas 绘制曲线图

代码:
<!Doctype Html>
 <html>
  <head>
   <title>Line Chart Demo</title>
   <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
   <style>
    body{background-color:#bfd0c4;}
    canvas{background-color:white;position:absolute;top:50%;left:50%;margin-left:-350px;margin-top:-250px;box-shadow: 3px 3px 3px #7e7a7c;}
  </style>
 </head>
 <body>
  <canvas width="700" height="400" id="canvas"> </canvas>
<script>
window.onload = function(){
  
  var multiData = {values:[
 { value0:[
   {x:"Jan",y:5},
   {x:"Feb",y:5},
   {x:"Mar",y:80},
   {x:"Apr",y:10},
   {x:"May",y:30},
   {x:"Jun",y:30},
   {x:"Jul",y:60},
   {x:"Aug",y:10}
  ]},
  { value1:[
    {x:"Jan",y:50},
    {x:"Feb",y:40},
    {x:"Mar",y:60},
    {x:"Apr",y:10},
    {x:"May",y:20},
    {x:"Jun",y:10},
    {x:"Jul",y:40},
    {x:"Aug",y:10}
   ]}
  ]	
 }//必须按照这个格式定义数据,关键字values value0 value1 ...... 
   /*
    *@param0: canvas 的id
    *@param1: json 数据
    *@param2: 坐标距离画布的间隙padding
    *@param3: 如果只有一条数据时数据的颜色,多条数据颜色随机
    *@param4: 点的颜色
    *@param5: 是否绘制背景线
    *@param6: 是否是多条数据
    */
   //先定义数据线的名字,再绘制数据
   LineChart.setKey(["2013","2014"]);
   LineChart.setData("canvas",multiData,60,"red","#333",true,true);
 }
		
   var LineChart={
    keynames:[],//数据信息数组
    can:undefined,
    ctx:undefined,
    width:undefined,
    lineColor:undefined,
    dotColor:undefined,
    isBg:false,
    isMultiData:false,
    setData:function(canId,data,padding,lineColor,dotColor,isBg,isMultiData){
      this.lineColor = lineColor;
      this.dotColor = dotColor;
      this.can = document.getElementById(canId);
      this.ctx = this.can.getContext("2d");
      this.isBg = isBg;
      this.isMultiData = isMultiData;
      this.drawXY(data,0,padding,this.can);
			
    },
   isMultiData:function(data){
      if(data.values.length>1){
        this.isMultiData = true;
       }
    },//是否是多条数据线
	
    drawXY:function(data,key,padding,can){
	this.ctx.lineWidth="4";
	this.ctx.strokeStyle="black";
	this.ctx.font = 'italic 15px sans-serif';
	this.ctx.beginPath();
	this.ctx.moveTo(padding,0)
	this.ctx.lineTo(padding,can.height-padding);
	this.ctx.lineTo(can.width,can.height-padding);
	this.ctx.stroke();
	var perwidth = this.getPixel(data,key,can.width,padding);//x 轴每一个数据占据的宽度
	var maxY =  this.getMax(data,0,this.isMultiData);//获得Y轴上的最大值
	var yPixel = this.getYPixel(maxY,can.height,padding).pixel;
	var ycount = this.getYPixel(maxY,can.height,padding).ycount;
	for( var i=0,ptindex;i< data.values[key]["value"+key].length;i++ ){
		ptindex = i+1;
		var x_x = this.getCoordX(padding,perwidth,ptindex);
		var x_y = can.height-padding+20;
		this.ctx.fillText(data.values[key]["value"+key][i].x,x_x,x_y,perwidth);
	}
	this.ctx.textAlign = "right"//y轴文字靠右写
	this.ctx.textBaseline = "middle";//文字的中心线的调整
	for(var i=0;i< ycount/10;i++){
	   this.ctx.fillText(i*10,padding-10,(ycount/10-i)*10*yPixel,perwidth);
	}
	if(this.isBg){
	   var x =  padding;
	   this.ctx.lineWidth="1";
	   this.ctx.strokeStyle="#e8e8e8";
	   for( var i=0;i< ycount/10;i++ ){
		var y = (ycount/10-i)*10*yPixel;
		this.ctx.moveTo(x,y);
		this.ctx.lineTo(can.width,y);
		this.ctx.stroke();
	  }
     }//选择绘制背景线
	this.ctx.closePath();
	this.drawData(data,0,padding,perwidth,yPixel,this.isMultiData);
    },//绘制XY坐标 线 以及点
	
    drawData:function(data,key,padding,perwidth,yPixel,isMultiData,lineColor){
  	if(!isMultiData){
		var keystr = "value"+key;
		this.ctx.beginPath();
		this.ctx.lineWidth="2";
		if(arguments[6]){
	        this.ctx.strokeStyle=lineColor;
	       }else{
		   this.ctx.strokeStyle=this.lineColor;
             }
		var startX = this.getCoordX(padding,perwidth,0);
		var startY = this.getCoordY(padding,yPixel,data.values[key][keystr][0].y);
		this.ctx.beginPath();
		this.ctx.lineWidth="2";
		for( var i=0;i< data.values[key][keystr].length;i++ ){
		  var x = this.getCoordX(padding,perwidth,i+1);
		  var y = this.getCoordY(padding,yPixel,data.values[key][keystr][i].y);
		  this.ctx.lineTo(x,y);
		}
		this.ctx.stroke();
		this.ctx.closePath();
		/*下面绘制数据线上的点*/
		this.ctx.beginPath();
		this.ctx.fillStyle=this.dotColor;
		for( var i=0;i< data.values[key][keystr].length;i++ ){
		   var x = this.getCoordX(padding,perwidth,i+1);
		   var y = this.getCoordY(padding,yPixel,data.values[key][keystr][i].y);
		   this.ctx.moveTo(x,y);
		   this.ctx.arc(x,y,3,0,Math.PI*2,true);//绘制数据线上的点
		   this.ctx.fill();
		}
		this.ctx.closePath();
		}else{//如果是多条数据线
		   for( var i=0;i< data.values.length;i++ ){
			var color = "rgb("+parseInt(Math.random()*256)+","+parseInt(Math.random()*256)+",
                         "+parseInt(Math.random()*256)+")";
			LineChart.drawData(data,i,padding,perwidth,yPixel,false,color);
			LineChart.drawKey(color,this.keynames[i],padding,i);
		     }
		  }
		},//绘制数据线和数据点
		getPixel:function(data,key,width,padding){
		  var count = data.values[key]["value"+key].length;
		  return (width-20-padding)/(count+(count-1)*1.5);	
		},//宽度
		getCoordX:function(padding,perwidth,ptindex){//下标从1开始 不是从0开始
			return 2.5*perwidth*ptindex+padding+10-2*perwidth;
		},//横坐标X 随ptindex 获得
		getCoordY:function(padding,yPixel,value){
			var y = yPixel*value;
			return this.can.height-padding-y;
		},//纵坐标X 随ptindex 获得(注意 纵坐标的算法是倒着的因为原点在最上面)
		 getYPixel:function(maxY,height,padding){
			var ycount = (parseInt(maxY/10)+1)*10+10;//y轴最大值
			return {pixel:(height-padding)/ycount,ycount:ycount};
		},//y轴的单位长度
        	
          getMax:function(data,key,isMultiData){
        	if(!isMultiData){
                var maxY = data.values[key]["value"+key][0].y;
        	  var length = data.values[key]["value"+key].length;
        	  var keystr = "value"+key;
        	  for( var i=1;i< length;i++ ){
        		if(maxY< data.values[key][keystr][i].y) maxY=data.values[key][keystr][i].y;
        	  }
        	  return maxY;//返回最大值 如果不是多数据
        	  }else{
        	    var maxarr=[];
        	    var count = data.values.length;//多条数据的数据长度
        	    for(var i=0;i< count;i++){
        		maxarr.push(LineChart.getMax(data,i,false));
        	    }
        	    var maxvalue = maxarr[0];
        	    for(var i=1;i< maxarr.length;i++){
        		maxvalue = (maxvalue< maxarr[i])?maxarr[i]:maxvalue; 
        	    }
        	    return maxvalue;
        	}//如果是多数据
           },
        	
        setKey:function(keynames){//keynames 是数组
        	for(var i=0;i< keynames.length;i++){
                this.keynames.push(keynames[i]);//存入数组中
        	}
         },
        
 	drawKey:function(color,keyname,padding,lineindex){
      		var x = padding+10;
      		var y = this.can.height - padding+20+13*(lineindex+1);
      		this.ctx.beginPath();
      		this.ctx.strokeStyle = color;
      		this.ctx.font="10px";
      		this.ctx.moveTo(x,y);
      		this.ctx.lineTo(x+50,y);
      		this.ctx.fillText(":"+keyname,x+80,y,30);
      		this.ctx.stroke();
      		this.ctx.closePath();
      	}	
  }
</script>
</body>
</html>

绘制曲线图的要点:

1.有一个画布,在画布上进行图表的显示

2.数据(数组格式、json等格式)

3.如何绘制x/y轴(找到x/y轴数据的最大值、最小值,确定原点、最大值及平均单位,进行绘制。绘制标题)

4.如何绘制数据线、数据点(同上)


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CanvasHTML5中提供的一种用于绘制图形的API,它可以用来创建各种复杂的图形,包括曲线图。在JavaScript中,我们可以使用`createImageData`、`getImageData`和`putImageData`等方法,以及`arc()`、`bezierCurveTo()`、`quadraticBezierCurveTo()`等函数来绘制曲线。 绘制曲线图的一般步骤如下: 1. **初始化 Canvas**:在HTML中创建一个`<canvas>`元素,并通过JavaScript获取其2D渲染上下文(`CanvasRenderingContext2D`)。 ```javascript var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); ``` 2. **设置起点和终点**:确定你要绘制曲线的起始点坐标和结束点坐标。 3. **绘制贝塞尔曲线(Bezier Curve)**:`bezierCurveTo()`函数可以用来创建一条由两个控制点决定的曲线。例如,绘制一条从`x1, y1`到`x2, y2`的曲线经过控制点`cx1, cy1`和`cx2, cy2`。 ```javascript ctx.beginPath(); ctx.moveTo(startX, startY); ctx.bezierCurveTo(cx1, cy1, cx2, cy2, endX, endY); ``` 4. **线宽和颜色**:可选地,你可以设置线条的宽度和颜色。 ```javascript ctx.lineWidth = 2; ctx.strokeStyle = 'black'; ``` 5. **绘制路径**:调用`stroke()`或`fill()`方法实际绘制路径,取决于你是想要描边还是填充。 ```javascript ctx.stroke(); // 如果你想让曲线显示出来 // 或者 ctx.fill(); // 如果你想填充曲线内部区域 ``` 6. **重复步骤**:如果你需要绘制多个曲线,只需再次调用上述步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值