gRaphael折线图绘制的值超出了坐标轴

3
使用gRaphael绘制毫秒级别的线图时,常常会出现数据点放置不一致的情况。最常见的是初始数据点在y轴左侧(如下面的fiddle中所示),有时最后一个数据点将超出视图框/超出x轴的终止点。
有人知道: 1)为什么会发生这种情况, 2)如何预防它, 3)如何检查它(如果我知道它已经发生了/超过了多少,我可以使用transform移动线条/点)。
我的代码:
var r = Raphael("holder"),
txtattr = { font: "12px sans-serif" };
var r2 = Raphael("holder2"),
txtattr2 = { font: "12px sans-serif" };

var x = [], y = [], y2 = [], y3 = [];

for (var i = 0; i < 1e6; i++) {
    x[i] = i * 10;
    y[i] = (y[i - 1] || 0) + (Math.random() * 7) - 3;
}
var demoX = [[1, 2, 3, 4, 5, 6, 7],[3.5, 4.5, 5.5, 6.5, 7, 8]];
var demoY = [[12, 32, 23, 15, 17, 27, 22], [10, 20, 30, 25, 15, 28]];

var xVals = [1288885800000, 1289929440000, 1290094500000, 1290439560000, 1300721700000,   1359499228000, 1359499308000, 1359499372000];
var yVals = [80, 76, 70, 74, 74, 78, 77, 72];
var xVals2 = [1288885800000, 1289929440000];
var yVals2 = [80, 76];

var lines = r.linechart(10, 10, 300, 220, xVals, yVals, { nostroke: false, axis: "0 0 1 1", symbol: "circle", smooth: true })
.hoverColumn(function () {
    this.tags = r.set();

    for (var i = 0, ii = this.y.length; i < ii; i++) {
        this.tags.push(r.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{ fill: "#fff" }, { fill: this.symbols[i].attr("fill") }]));
        }
    }, function () {
        this.tags && this.tags.remove();
        });

lines.symbols.attr({ r: 3 });


var lines2 = r2.linechart(10, 10, 300, 220, xVals2, yVals2, { nostroke: false, axis: "0 0 1 1", symbol: "circle", smooth: true })
.hoverColumn(function () {
    this.tags = r2.set();

    for (var i = 0, ii = this.y.length; i < ii; i++) {
        this.tags.push(r.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{ fill: "#fff" }, { fill: this.symbols[i].attr("fill") }]));
        }
    }, function () {
        this.tags && this.tags.remove();
        });

lines2.symbols.attr({ r: 3 });

我需要使用gRaphael,并且x轴的单位必须为毫秒(稍后会使用自定义日期字符串标记它)。

主要示例fiddle:http://jsfiddle.net/kcar/aNJxf/

次要示例fiddle(页面上第4个示例经常显示两个轴错误):http://jsfiddle.net/kcar/saBnT/

根本原因是snapEnds函数(g.raphael.js中的第718行),它做的舍入,在某些情况下,可以接受,在其他情况下,会从/添加年份。

尚未完全跟踪此点之后的所有内容,但由于每次舍入变得疯狂并且不是每次都不正确地放置数据点时,我将继续假定这会导致计算图表列时出现问题,还在发送到snapEnds之前的值确切无误只是确认其不仅是接收了错误的数据。

来自g.raphael.js的该函数代码:

snapEnds: function(from, to, steps) {
    var f = from,
        t = to;

    if (f == t) {
        return {from: f, to: t, power: 0};
    }

    function round(a) {
        return Math.abs(a - .5) < .25 ? ~~(a) + .5 : Math.round(a);
    }

    var d = (t - f) / steps,
        r = ~~(d),
        R = r,
        i = 0;

    if (r) {
        while (R) {
            i--;
            R = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
        }

        i ++;
    } else {
        if(d == 0 || !isFinite(d)) {
            i = 1;
        } else {
            while (!r) {
                i = i || 1;
                r = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
                i++;
            }
        }

        i && i--;
    }

    t = round(to * Math.pow(10, i)) / Math.pow(10, i);

    if (t < to) {
        t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i);
    }

    f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i);
    return { from: f, to: t, power: i };
},

这些错误大多数已经被消除了(它们仍然会发生,但不像以前那么频繁),如果我将毫秒转换为小时,这在我的情况下仍不是理想的解决方案,但对于其他遇到相同问题的人可能是一个快速修复。 - kcar
只是为了明确,这里所指的是自纪元以来的毫秒/小时。 - kcar
在调查过程中,似乎有时候只是线条比例不对(有时候线条太长,因此第一个和最后一个点超出了它们应该在的位置,有时候线条太短),有时候只是定位不准确。就我而言,我不知道为什么相同的数据/代码会导致完全不同的错误。 - kcar
我发现这个答案很有用 http://stackoverflow.com/questions/7075013/how-do-you-get-a-y-axis-that-starts-at-zero-in-graphael-if-none-of-your-values - fireydude
4个回答

2

从snapEnds中删除了四舍五入的无谓操作,现在没有任何问题,无论是对于任何坐标系还是图表的其他区域。如果您发现了任何问题,请告诉我。

现在g.raphael.js中该函数的代码如下:

snapEnds: function(from, to, steps) {
     return {from: from, to: to, power: 0};       
},

1

你好,如果你注释这个:

        if (valuesy[i].length > width - 2 * gutter) {
            valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
            len = width - 2 * gutter;
        }

        if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
            valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
        }

在g.line.js中,它似乎解决了这个问题,并且还解决了y轴上数值类似的问题。

感谢您的建议,将g.raphael.js中snapEnds函数的主体注释掉似乎解决了问题,三个月后我没有发现任何负面影响。 - kcar

1

我从v0.50升级到v0.51后,问题得到了解决。


不幸的是,我已经使用了0.51版本,但我知道在g.raphael git上建议了几种不同的解决方法,所以我猜修复程序正在自行工作中。 - kcar

0

仍然不确定为什么会发生这种情况,添加透明集合并不是一个理想的选择。 检查数据点是否在图形外部呈现的最简单方法似乎是获取轴集的边界框和数据点的边界框,并检查x和x2值之间的差异。

如果有人可以帮我缩放数据点集,或者找出如何完全避免这种情况发生,我仍然会感激/赞同答案。

//assuming datapoints  is the Raphael Set for the datapoints, axes is the 
//Raphael Set for the axis, and datalines is the Raphael Set for the 
//datapoint lines
var pointsBBox = datapoints.getBBox();
var axesBBox = axes.getBBox();
var xGapLeft = Math.ceil(axesBBox.x - pointsBBox.x); 
//rounding up to integer to simplify, and the extra boost from y-axis doesn't 
//hurt, <1 is a negligible distance in transform
var xGapRight = Math.ceil(axesBBox.x2 - pointsBBox.x2);
var xGap = 0;
if(xGapLeft > 0){
     datapoints.transform('t' +xGapLeft +',0');
     datalines.transform('t' +xGapLeft +',0');
     xGap = xGapLeft;
}else if (xGapRight < 0) { //using else if because if it is a scale issue it will
//be too far right & too far left, meaning both are true and using transform will
//just shift it right then left and you are worse off than before, using 
//set.transform(scale) works great on dataline but when using on datapoints scales
// symbol radius not placement
     if (xGapLeft < 0 && xGapRight < xGapLeft) { xGapRight = xGapLeft; }  
//in this case the initial point is right of y-axis, the end point is right of 
//x-axis termination, and the difference between last point/axis is greater than
//difference between first point/axis

     datapoints.transform('t' +xGapRight +',0');
     datalines.transform('t' +xGapRight +',0');
     xGap = xGapRight;
}
rehookHoverOverEvent(xGap);  //there are so many ways to do this just leaving it
//here as a call to do so, if you don't the hover tags will be over the original 
//datapoints instead of the new location, at least they were in my case.

说实话,我并不是很喜欢这个修复方案,因为它没有解决根本问题,而且如果行太长或太短(缩放问题),它也无法工作,但它是一个对我有效的临时措施,可能对其他人也有用,但这就是为什么我没有选择它作为“被接受的答案”。 - kcar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接