在 canvas 折线图中显示负值
Display negative values in canvas line graph
我正在使用 html5 canvas 元素绘制折线图。该图表适用于正值。但是当提供负值时,图表绘制不正确。
这是我试过的。任何帮助将不胜感激。
http://jsfiddle.net/nshX6/142/
function getMinY () {
var min = 0;
for(var i = 0; i < data.values.length; i ++) {
if(data.values[i].Y < min) {
min = data.values[i].Y;
}
}
return Math.ceil(min);
}
尝试修改此参数:
var xPadding = 30;
var yPadding = 30;
收件人:
var xPadding = 30;
var yPadding = 100;
之后你需要把Y步调大一点。
编辑
如果您有动态数据,则需要对值进行规范化。
步骤 1:找到 Y 的最小值
步骤 2:如果最小值小于零 (0),则需要将所有值标准化为正数。将该值添加到 array
的每个元素
步骤 3:将 Y 轴移动到新位置。
您可以使用以下工具函数来构建灵活的图形。
您的灵活图表将能够显示任何范围的数据,并且它将始终适合可用的canvas尺寸。
calcSourceMinMax: 计算数据数组的最小值和最大值。
mapRange: 获取任何数据值并将其映射为比例值,该比例值保证在图形可显示宽度和高度的最小值和最大值内。这允许您的数据数组包含任何范围的值,并且永远不会落在图形显示区域之外。
getDisplayXY: 获取指定的 x,y 数据值并找到其在图形上的显示 X,Y 坐标。
这是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var xPadding = 40;
var yPadding = 30;
// Notice I changed The X values
var data = { values:[
{ X: 0, Y: -120 },
{ X: 2, Y: 28 },
{ X: 3, Y: 18 },
{ X: 4, Y: 34 },
{ X: 5, Y: 40 },
{ X: 6, Y: 80 },
{ X: 7, Y: 80 }
]};
// calc the drawable graph boundaries
var graphLeft=xPadding;
var graphRight=canvas.width-xPadding;
var graphTop=yPadding;
var graphBottom=canvas.height-yPadding;
// graph styling
var dotRadius=3;
// calc the min & max values of data.values (calc both X & Y ranges)
var rangeX=calcSourceMinMax(data.values,'X');
var rangeY=calcSourceMinMax(data.values,'Y');
// draw the graph content
var starting=getDisplayXY(data.values[0].X,data.values[0].Y);
dot(starting,dotRadius);
for(var i=1;i<data.values.length;i++){
var ending=getDisplayXY(data.values[i].X,data.values[i].Y);
connector(starting,ending);
dot(ending,dotRadius);
starting=ending;
}
// draw the graph axes
var y0=getDisplayXY(graphLeft,0).displayY;
ctx.beginPath();
ctx.moveTo(graphLeft,graphTop);
ctx.lineTo(graphLeft,graphBottom);
ctx.moveTo(graphLeft,y0);
ctx.lineTo(graphRight,y0);
ctx.strokeStyle='#D3E';
ctx.stroke();
// draw the graph legends
ctx.textAlign='right';
ctx.textBaseline='middle';
var y0=getDisplayXY(graphLeft,0).displayY;
var yMin=getDisplayXY(graphLeft,rangeY.min).displayY;
var yMax=getDisplayXY(graphLeft,rangeY.max).displayY;
var xMax=getDisplayXY(graphRight,rangeX.max).displayX;
ctx.fillText(rangeY.min,graphLeft-10,yMin);
ctx.fillText(0,graphLeft-10,y0);
ctx.fillText(rangeY.max,graphLeft-10,yMax);
ctx.fillText(rangeX.max,graphRight+10,y0);
///////////////////////////////////
// HELPER FUNCTIONS
///////////////////////////////////
//
function getDisplayXY(valueX,valueY){
// calc the display X & Y from data.values[i]
x=mapRange(valueX,rangeX.min,rangeX.max,graphLeft,graphRight);
// Note: canvas y values increase going downward
// so swap graphTop & graphBottom
y=mapRange(valueY,rangeY.min,rangeY.max,graphBottom,graphTop);
return({displayX:x,displayY:y})
}
//
function connector(starting,ending){
ctx.beginPath();
ctx.moveTo(starting.displayX,starting.displayY);
ctx.lineTo(ending.displayX,ending.displayY);
ctx.stroke();
}
//
function dot(position,radius){
ctx.beginPath();
ctx.moveTo(position.displayX,position.displayY);
ctx.arc(position.displayX,position.displayY,radius,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
// map source values into a designated range
function mapRange(value, sourceLow, sourceHigh, mappedLow, mappedHigh) {
return mappedLow + (mappedHigh - mappedLow) * (value - sourceLow) / (sourceHigh - sourceLow);
}
// mapping helper function
function calcSourceMinMax(a,prop){
var min=1000000;
var max=-1000000;
for(var i=0;i<a.length;i++){
var value=a[i][prop];
if(value<min){min=value;}
if(value>max){max=value;}
}
return({min:min,max:max});
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=350 height=300></canvas>
您将希望根据您的设计需要设置图形样式。这个最小的例子显示了一个包含 x、y 轴和最小、最大值范围的图例。
此外,x 轴位于 y=0 值处。您还需要检查您的 y 值范围内是否确实存在 y=0。如果不是,您可以移动图形底部的 x 轴。
祝你项目顺利!
我正在使用 html5 canvas 元素绘制折线图。该图表适用于正值。但是当提供负值时,图表绘制不正确。
这是我试过的。任何帮助将不胜感激。
http://jsfiddle.net/nshX6/142/
function getMinY () {
var min = 0;
for(var i = 0; i < data.values.length; i ++) {
if(data.values[i].Y < min) {
min = data.values[i].Y;
}
}
return Math.ceil(min);
}
尝试修改此参数:
var xPadding = 30;
var yPadding = 30;
收件人:
var xPadding = 30;
var yPadding = 100;
之后你需要把Y步调大一点。
编辑
如果您有动态数据,则需要对值进行规范化。
步骤 1:找到 Y 的最小值
步骤 2:如果最小值小于零 (0),则需要将所有值标准化为正数。将该值添加到 array
的每个元素步骤 3:将 Y 轴移动到新位置。
您可以使用以下工具函数来构建灵活的图形。
您的灵活图表将能够显示任何范围的数据,并且它将始终适合可用的canvas尺寸。
calcSourceMinMax: 计算数据数组的最小值和最大值。
mapRange: 获取任何数据值并将其映射为比例值,该比例值保证在图形可显示宽度和高度的最小值和最大值内。这允许您的数据数组包含任何范围的值,并且永远不会落在图形显示区域之外。
getDisplayXY: 获取指定的 x,y 数据值并找到其在图形上的显示 X,Y 坐标。
这是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var xPadding = 40;
var yPadding = 30;
// Notice I changed The X values
var data = { values:[
{ X: 0, Y: -120 },
{ X: 2, Y: 28 },
{ X: 3, Y: 18 },
{ X: 4, Y: 34 },
{ X: 5, Y: 40 },
{ X: 6, Y: 80 },
{ X: 7, Y: 80 }
]};
// calc the drawable graph boundaries
var graphLeft=xPadding;
var graphRight=canvas.width-xPadding;
var graphTop=yPadding;
var graphBottom=canvas.height-yPadding;
// graph styling
var dotRadius=3;
// calc the min & max values of data.values (calc both X & Y ranges)
var rangeX=calcSourceMinMax(data.values,'X');
var rangeY=calcSourceMinMax(data.values,'Y');
// draw the graph content
var starting=getDisplayXY(data.values[0].X,data.values[0].Y);
dot(starting,dotRadius);
for(var i=1;i<data.values.length;i++){
var ending=getDisplayXY(data.values[i].X,data.values[i].Y);
connector(starting,ending);
dot(ending,dotRadius);
starting=ending;
}
// draw the graph axes
var y0=getDisplayXY(graphLeft,0).displayY;
ctx.beginPath();
ctx.moveTo(graphLeft,graphTop);
ctx.lineTo(graphLeft,graphBottom);
ctx.moveTo(graphLeft,y0);
ctx.lineTo(graphRight,y0);
ctx.strokeStyle='#D3E';
ctx.stroke();
// draw the graph legends
ctx.textAlign='right';
ctx.textBaseline='middle';
var y0=getDisplayXY(graphLeft,0).displayY;
var yMin=getDisplayXY(graphLeft,rangeY.min).displayY;
var yMax=getDisplayXY(graphLeft,rangeY.max).displayY;
var xMax=getDisplayXY(graphRight,rangeX.max).displayX;
ctx.fillText(rangeY.min,graphLeft-10,yMin);
ctx.fillText(0,graphLeft-10,y0);
ctx.fillText(rangeY.max,graphLeft-10,yMax);
ctx.fillText(rangeX.max,graphRight+10,y0);
///////////////////////////////////
// HELPER FUNCTIONS
///////////////////////////////////
//
function getDisplayXY(valueX,valueY){
// calc the display X & Y from data.values[i]
x=mapRange(valueX,rangeX.min,rangeX.max,graphLeft,graphRight);
// Note: canvas y values increase going downward
// so swap graphTop & graphBottom
y=mapRange(valueY,rangeY.min,rangeY.max,graphBottom,graphTop);
return({displayX:x,displayY:y})
}
//
function connector(starting,ending){
ctx.beginPath();
ctx.moveTo(starting.displayX,starting.displayY);
ctx.lineTo(ending.displayX,ending.displayY);
ctx.stroke();
}
//
function dot(position,radius){
ctx.beginPath();
ctx.moveTo(position.displayX,position.displayY);
ctx.arc(position.displayX,position.displayY,radius,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
// map source values into a designated range
function mapRange(value, sourceLow, sourceHigh, mappedLow, mappedHigh) {
return mappedLow + (mappedHigh - mappedLow) * (value - sourceLow) / (sourceHigh - sourceLow);
}
// mapping helper function
function calcSourceMinMax(a,prop){
var min=1000000;
var max=-1000000;
for(var i=0;i<a.length;i++){
var value=a[i][prop];
if(value<min){min=value;}
if(value>max){max=value;}
}
return({min:min,max:max});
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=350 height=300></canvas>
您将希望根据您的设计需要设置图形样式。这个最小的例子显示了一个包含 x、y 轴和最小、最大值范围的图例。
此外,x 轴位于 y=0 值处。您还需要检查您的 y 值范围内是否确实存在 y=0。如果不是,您可以移动图形底部的 x 轴。
祝你项目顺利!