Javascript [Safari/Chrome致命错误]HTML5画布不适用于特定情况,但Firefox做得很好

Javascript [Safari/Chrome致命错误]HTML5画布不适用于特定情况,但Firefox做得很好,javascript,html,google-chrome,canvas,safari,Javascript,Html,Google Chrome,Canvas,Safari,我使用html5画布构建了一个函数图软件。 有一个严重的错误,但我不知道发生了什么 也就是说,当我打电话时: yOFxGraph(plotFUNCinputYofX,-4,5,-4,4,"rgb(66,44,255)",1); Mac上的Firefox26/Chrome32/Safari7一切正常 但是,当我更改时,只有一个小参数,如: yOFxGraph(plotFUNCinputYofX,-5,5,-4,4,"rgb(66,44,255)",1); 图形在Chrome/Safari中消失

我使用html5画布构建了一个函数图软件。 有一个严重的错误,但我不知道发生了什么

也就是说,当我打电话时:

yOFxGraph(plotFUNCinputYofX,-4,5,-4,4,"rgb(66,44,255)",1);
Mac上的Firefox26/Chrome32/Safari7一切正常

但是,当我更改时,只有一个小参数,如:

yOFxGraph(plotFUNCinputYofX,-5,5,-4,4,"rgb(66,44,255)",1);
图形在Chrome/Safari中消失,但在Firefox中仍能正常工作

下面是整个代码,你能告诉我怎么解决吗?非常感谢你。 这个错误怎么会发生在主要浏览器上!?不管怎样,代码是如此简单

<!doctype html>
<html>
<body onload="draw()">
    <script>
    function plotFUNCinputYofX(x) {return 1/Math.sin(x);}

    function draw() {
       yOFxGraph(plotFUNCinputYofX,-4,5,-4,4,"rgb(66,44,255)",1);
    }

    function yOFxGraph (func,xFrom,xTo,yFrom,yTo,color,thick) {
        var canvas = document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        ctx.lineWidth = thick;
        ctx.strokeStyle = color;

        var Xunit = canvas.width/(xTo-xFrom);
        var Yunit = canvas.height/(yTo-yFrom);
        var samplingX=(xTo-xFrom)/400;/*I only sample 400 points whatever the scale is.*/
        var xx = xFrom;
        ctx.beginPath();
        ctx.moveTo(0 , canvas.height-(func(xx)-yFrom)*Yunit);

        function pivoting(){
            xx+=samplingX;
            ctx.lineTo((xx-xFrom)*Xunit , canvas.height-(func(xx)-yFrom)*Yunit);
        }
        if(xFrom<xTo){while(xx<xTo){pivoting()}}
        else if(xFrom>xTo){while(xx>xTo){pivoting()}}
        ctx.stroke();
    }
    </script>
    <canvas id="canvas" width="500" height="500"></canvas>
</body>
</html>

函数plotFUNCinputYofX(x){return 1/Math.sin(x);}
函数绘图(){
yOFxGraph(plotFUNCinputYofX,-4,5,-4,4,“rgb(66,44255)”,1);
}
函数yOFxGraph(func、xFrom、xTo、yFrom、yTo、color、thick){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
ctx.线宽=厚;
ctx.strokeStyle=颜色;
var Xunit=canvas.width/(xTo xFrom);
var Yunit=画布高度/(yTo yFrom);
var samplingX=(xTo xFrom)/400;/*无论比例如何,我只对400个点进行采样*/
var xx=xFrom;
ctx.beginPath();
ctx.moveTo(0,画布高度-(func(xx)-yFrom)*Yunit);
函数旋转(){
xx+=取样x;
ctx.lineTo((xx xFrom)*Xunit,canvas.height-(func(xx)-yFrom)*Yunit);
}
if(xFromxTo){pivoting()}}
ctx.stroke();
}

您似乎发现浏览器在绘图时处理无穷大(或可能是巨大值)的方式有所不同

首先,让我们注意到,通过使用-5到5,允许精确值x=0,这会导致
1/sin(0)
,即
无穷大(或者有一些浮点舍入错误,可能是一个非常大的正值或负值)

FireFox显然忽略了这一点。也许它忽略了这一点,但是继续在剩余的部分上划,好像它不在那里,或者它把它当作一个断线(我会考虑NANS的正确、直观的行为)。 但在Chrome和Safari中,这个无限或巨大的数字会导致整个笔划无效,因此它不会绘制任何笔划

简单的解决方法是确保你的价值是合理的。这里有一个限制边界的检查:(您可能希望使用更宽的边界,或者以不同的方式处理离开屏幕)

var yy=func(xx);
如果(!(yy>yFrom))yy=yFrom;

如果(!(yy基于Dave的想法,我最终编辑了我的代码,如下所示:

/*Safari7 & Chrome32 canvas bug*/
var Y=canvas.height-(func(xx)-yFrom)*Yunit;
if(0<=Y&&Y<=canvas.height){ctx.moveTo(0 , Y);}
else if(Y>canvas.height){Y=canvas.height+1;ctx.moveTo(0 , Y);}
else if(Y<0){Y=-1;ctx.moveTo(0 , Y);}
/*Safari7 & Chrome32 canvas bug*/
function pivoting(){
    xx+=samplingX;
    /*Safari7 & Chrome32 canvas bug*/
    Y=canvas.height-(func(xx)-yFrom)*Yunit;
    if(0<=Y&&Y<=canvas.height){ctx.lineTo((xx-xFrom)*Xunit , Y);}
    else if(Y>canvas.height){Y=canvas.height+1;ctx.lineTo((xx-xFrom)*Xunit , Y);}
    else if(Y<0){Y=-1;ctx.lineTo((xx-xFrom)*Xunit , Y);}
    /*Safari7 & Chrome32 canvas bug*/
}
/*Safari7和Chrome32画布错误*/
变量Y=画布高度-(func(xx)-yFrom)*Yunit;

如果(0我发现,当我将采样点从400点减少到255点时,Safari和Chrome将再次生效。然而,当采样点减少到200点时,Safari再次生效,Chrome也无法正常工作。这是否与GPU加速有关???或者这是Webkit引擎的浮点数计算问题?我在这里可能是错的,但这是错的似乎一个bug报告已经准备好了。是的,我已经准备好了。并且仍然在思考一些棘手的方法来克服这个问题。有趣的是,现在正在查看您的代码。对于任何其他想要快速进行更改的人,我在这里把它放在了一个小提琴上:嘿,Dave!非常感谢您的分析和提供的解决方案。我认为您的分析是合理的。但是,当我尝试在x=-5~5的范围内绘制1/sin(x+5),Safari和Chrome都很好。这意味着,问题的原因可能不是“被零除”,而是看起来像随机崩溃。顺便说一句,我已经重新测试了1/0。Javascript判断为“无穷大”,但不是“NaN”.你认为呢?无穷大仍然可以用Javascript计算。比如无穷大+3=无穷大。在我的分析中,我将交替处理NaN、无穷大和超大数,因为返回哪一个具体数字取决于具体情况和累积的舍入误差。它们的本质是相同的;这是一个,出于所有实际目的,这是毫无意义的。绘图方法完全有理由被它弄糊涂(可能是因为它使用定点精度,而且非常大的数字会导致溢出)。要解决它,请按照我在回答中建议的方式钳制值,问题就会消失。要修复它,请提交一个bug,然后等待(您这样做了).公平地说,是的,1/0是无穷大,0/0是NaN。我弄错了,但正如我所说的,其余的分析仍然有效。嘿,戴夫!谢谢,你的分析太棒了!我用你的想法解决了这个问题。
/*Safari7 & Chrome32 canvas bug*/
var Y=canvas.height-(func(xx)-yFrom)*Yunit;
if(0<=Y&&Y<=canvas.height){ctx.moveTo(0 , Y);}
else if(Y>canvas.height){Y=canvas.height+1;ctx.moveTo(0 , Y);}
else if(Y<0){Y=-1;ctx.moveTo(0 , Y);}
/*Safari7 & Chrome32 canvas bug*/
function pivoting(){
    xx+=samplingX;
    /*Safari7 & Chrome32 canvas bug*/
    Y=canvas.height-(func(xx)-yFrom)*Yunit;
    if(0<=Y&&Y<=canvas.height){ctx.lineTo((xx-xFrom)*Xunit , Y);}
    else if(Y>canvas.height){Y=canvas.height+1;ctx.lineTo((xx-xFrom)*Xunit , Y);}
    else if(Y<0){Y=-1;ctx.lineTo((xx-xFrom)*Xunit , Y);}
    /*Safari7 & Chrome32 canvas bug*/
}