【问题标题】:Display negative values in canvas line graph在画布折线图中显示负值
【发布时间】:2015-02-11 04:14:12
【问题描述】:

我正在使用 html5 画布元素来绘制折线图。该图表适用于正值。但是当提供负值时,图表无法正确绘制。

这是我尝试过的。任何帮助将不胜感激。

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

【问题讨论】:

    标签: javascript html canvas charts


    【解决方案1】:

    以下是一些可用于构建灵活图表的工具函数。

    您的灵活图表将能够显示任何范围的数据,并且它将始终适合可用的画布尺寸。

    calcSourceMinMax:计算数据数组的最小值和最大值。

    ma​​pRange: 获取任何数据值并将其映射为一个比例值,该值保证在图形可显示宽度和高度的最小值和最大值范围内。这允许您的数据数组包含任何范围的值,并且永远不会超出图形显示区域。

    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;}
    &lt;canvas id="canvas" width=350 height=300&gt;&lt;/canvas&gt;

    您将需要根据您的设计需求来设置图表的样式。这个最小的示例显示了一个包含 x、y 轴和最小、最大值范围的图例。

    此外,x 轴位于 y=0 值。您还需要检查在您的 y 值范围内是否确实存在 y=0。如果没有,您可以移动图表底部的 x 轴。

    祝你的项目好运!

    【讨论】:

    • 完全覆盖。但帮助很大。非常感谢。
    【解决方案2】:

    尝试修改此参数:

    var xPadding = 30;
    var yPadding = 30;
    

    收件人:

    var xPadding = 30;
    var yPadding = 100;
    

    之后你需要把Y步变大。

    编辑

    如果您有动态数据,则需要对值进行规范化。

    第 1 步:找到 Y 的最小值

    第 2 步:如果最小值小于零 (0),您需要将所有值标准化为正数。将该值添加到数组的每个元素中

    第 3 步:将 Y 轴移动到新位置。

    【讨论】:

    • 如果数据是动态的呢?
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 2019-06-12
    • 2020-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多