HTML5 Canvas 当 window 很大时,alpha 透明度在 firefox 中对曲线不起作用

HTML5 Canvas alpha transparency doesn't work in firefox for curves when window is big

我在 HTML5 canvas 上绘制一条曲线,并使用 alpha 透明度创建发光效果,方法是在下面绘制一条 alpha 小于 1 的较粗版本的曲线,然后在顶部绘制更细的曲线(我正在使用多个递归级别来执行此操作)。

好的,问题来了。它的工作方式完全符合我在 Chrome 中的要求,提供了美丽的发光效果。但是在 Firefox 中,如果我的浏览器尺寸大于大约 300 像素的高度,alpha 将无法正确呈现(是的,这听起来很疯狂,但出于某种原因,它实际上就是这样做的)。如果我将浏览器的大小调整得非常小,那么 alpha 会突然起作用,我会得到令人惊叹的光芒。一旦我将 window 设置为合理的大小,alpha 就不再起作用,所以我得到的不是一条发光的线,而是一条非常粗的线。 :( 代码如下。

HTML:

<body>
    <canvas id="viewport">
    <script type="text/javascript" src="scripts/render.js"></script>
</body>

CSS:

* {
    background-color:#000000;
    padding:0px;
    margin:0px;
    width:100%;
    height:100%;
    overflow:hidden;
}

#viewport {
    border:0px;
}

Javascript:

window.viewport = document.getElementById("viewport");
window.context = viewport.getContext("2d");
window.xFactor = 1;
window.yFactor = 1;

function initializeViewport() {
    maximizeViewport();
    setFactors();
}

function maximizeViewport() {
    viewport.width = window.innerWidth;
    viewport.height = window.innerHeight;
}

function setFactors() {
    xFactor = window.innerWidth / 100;
    yFactor = window.innerHeight / 100;
}

function absX(x) {
    return Math.floor(x * xFactor);
}

function absY(y) {
    return Math.floor(y * yFactor);
}


function drawQuadraticCurve(startX, startY, controlX, controlY, endX, endY, lineWidth, gradient, alpha, glowiness, glowLevel) {
    glowLevel = (typeof glowLevel === 'undefined') ? 0 : glowLevel;

    // Draw the glow first
    if (glowLevel < glowiness) {
        drawQuadraticCurve(startX, startY, controlX, controlY, endX, endY, lineWidth + Math.sqrt(glowLevel), gradient, alpha*0.65, glowiness, glowLevel + 1);
    }

    // Then draw the curve
    context.beginPath();
    context.moveTo(absX(startX), absY(startY));
    context.quadraticCurveTo(absX(controlX), absY(controlY), absX(endX), absY(endY));
    context.lineWidth = lineWidth;
    context.strokeStyle = gradient;
    context.globalAlpha = alpha;
    context.shadowColor = "#FFFFFF";
    context.shadowBlur = 0;
    context.shadowOffsetX = 0;
    context.shadowOffsetY = 0;
    context.stroke();
}

    function createRadialGradient(colors, innerX, innerY, innerR, outerX, outerY, outerR) {
    var gradient = context.createRadialGradient(absX(innerX),absY(innerY),Math.min(absX(innerR/2), absY(innerR/2)),absX(outerX),absY(outerY),Math.min(absX(outerR/2), absY(outerR/2)));
    var gradientLength = colors.length;
    for (i=0; i<gradientLength; i++) {
        gradient.addColorStop(colors[i][0], colors[i][1]);
    }

    return gradient;
}


initializeViewport();
drawQuadraticCurve(80,65,20,70,70,10, 1,createRadialGradient([[0,"#FFFFFF"],[0.7,"#33CCFF"],[1,"#9944FF"]],50,50,1,50,50,90),1,8,0);

它在 Chrome 中工作的屏幕截图:http://i.imgur.com/brVT2i6.png

无法在 Firefox 中运行的屏幕截图:http://i.imgur.com/63Z4PJY.png

在我将 window 的大小调整得离谱之后它在 Firefox 中运行的屏幕截图:http://i.imgur.com/d9AihEu.png

第一个 可行的解决方案 获得赞成票和绿色复选标记!耶!

这确实是一条评论,但它不适合分配给评论的 space。 :-)

我咨询过 Html5 Canvas 的全知神谕——w3.org。

如果您指定一个零阴影模糊(正如您所做的那样),规范说应该没有应用阴影。

这意味着具有较大 canvas 大小的 FF 正确应用 w3 标准(不绘制任何阴影)并且 Chrome 和 FF(较小的版本)错误地应用了本不应应用的阴影。

http://www.w3.org/TR/2dcontext/

Shadows are only drawn if the opacity component of the alpha component of the color of shadowColor is non-zero and either the shadowBlur is non-zero, or the shadowOffsetX is non-zero, or the shadowOffsetY is non-zero.

因此,要具有跨浏览器兼容性,您不能依赖 shadowBlur=0 时渲染中的怪癖。您必须在 "rules".

中以另一种方式创建您的光晕

这是一条发光的二次曲线,由细小的、独立的线段组成——每条线段都有不同的颜色。等于段颜色的 shadowColor 会导致发光。渲染跨浏览器(包括 FF)兼容。

(可以控制线宽和发光强度)

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// variables to define colors -- use hsl instead of rgb
var hue=10;
var hueShift=4;

// define the quadratic curve
var startPt={x:350,y:100};
var controlPt={x:0,y:250};
var endPt={x:350,y:400};

// variables defining the starting & ending point of 
// the current line segment.
var newXY=startPt;
var oldXY=startPt;

// the current interval along the quadratic curve
// (used to calc an x,y along the curve)
// (t is kind-of like a percentage along the curve--kind of but not)
var t=0;

// the unshadowed linewidth
ctx.lineWidth=1;

// the shadow to apply around the line
ctx.shadowBlur=7;

// round the endcaps to visually blend the line segments
ctx.lineCap='round';

// start with a black-filled canvas
ctx.fillStyle='black';
ctx.fillRect(0,0,cw,ch);

// start the animation
requestAnimationFrame(animate);


function animate(time){ 

  // calculate a new x,y along the curve
  var T=t/100;
  var newXY=getQuadraticBezierXYatT(startPt,controlPt,endPt,T);

  // change the color for this segment
  hue=(hue+hueShift)%360;

  // draw this line segment with a shadow-glow
  glowLine(oldXY,newXY,hue);

  // set old=new in preparation for the next loop
  oldXY=newXY;

  // request another animation loop intil reaching 100
  if(++t<100){
    requestAnimationFrame(animate);
  }
}

function glowLine(oldXY,newXY,hue){
  // calculate the hsl color given the new hue
  var hsl="hsl(" + (hue % 360) + ",99%,50%)";
  // draw a glowing line segment
  // (==a line segment with a shadow of the same color as the line segment)
  ctx.beginPath();
  ctx.moveTo(oldXY.x,oldXY.y);
  ctx.lineTo(newXY.x,newXY.y);
  ctx.fillStyle= hsl
  ctx.strokeStyle=hsl;
  ctx.shadowColor=hsl;
  // overdraw the line segment so it really stands out
  for(var i=0;i<6;i++){
    ctx.stroke();
  }
}

// calculate an [x,y] along a quadratic curve given an interval T
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
  var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
  var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
  return( {x:x,y:y} );
}
body{ background-color:ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=500 height=500></canvas>