html5 – CreateJS带矩阵的径向渐变

我正在将Flash应用程序转换为
HTML5 Canvas.大多数开发都已完成,但是为了处理颜色,flash应用程序中有这样的代码:

matrix = new Matrix ();
matrix.createGradientBox (600, ColorHeight * 1200, 0, 80, ColorHeight * -600);
Animation_gradient_mc.clear ();
Animation_gradient_mc.beginGradientFill (fillType, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio);

CreateJS中的径向渐变声明如下:

beginRadialGradientFill(colors, ratios, x0, y0, r0, x1, y1, r1 )

有没有人知道将矩阵应用于渐变填充的方法?

任何帮助,将不胜感激.

提前致谢

编辑

以下是我尝试重现的渐变的一些示例:

《html5 – CreateJS带矩阵的径向渐变》

如您所见,它以标准径向渐变开始.

但是,它也可能看起来很拉伸,我认为这是矩阵有用的地方.

《html5 – CreateJS带矩阵的径向渐变》

我试图通过创建一个带有矩阵的createjs.Graphics.Fill来创建相同的效果,但它似乎没有做任何事情:

var matrix = new VacpMatrix();
    matrix.createGradientBox(
        600,
        discharge_gradient.color_height * 1200,
        0,
        80,
        discharge_gradient.color_height * -600
    );

    // test_graphics.append(new createjs.Graphics.Fill('#0000ff', matrix));

    console.log('matrix', matrix);

    test_graphics.append(new createjs.Graphics.Fill('#ff0000', matrix).radialGradient(
        discharge_gradient.colors,
        discharge_gradient.ratios,
        discharge_gradient.x0,
        discharge_gradient.y0,
        discharge_gradient.r0,
        discharge_gradient.x1,
        discharge_gradient.y1,
        discharge_gradient.r1
    ));

    var discharge_shape = new createjs.Shape(test_graphics);

我扩展了Matrix2d类,使用openfl项目中的代码添加了一个createGradientBox方法:

p.createGradientBox = function (width, height, rotation, tx, ty) {
    if (_.isUndefined(rotation) || _.isNull(rotation)) {
        rotation = 0;
    }

    if (_.isUndefined(tx) || _.isNull(tx)) {
        tx = 0;
    }

    if (_.isUndefined(ty) || _.isNull(ty)) {
        ty = 0;
    }

    var a = width / 1638.4,
        d = height / 1638.4;

    // Rotation is clockwise
    if (rotation != 0) {
        var cos = math.cos(rotation),
            sin = math.sin(rotation);

        this.b = sin * d;
        this.c = -sin * a;
        this.a = a * cos;
        this.d = d * cos;
    } else {
        this.b = 0;
        this.c = 0;
    }

    this.tx = tx + width / 2;
    this.ty = ty + height / 2;
}

我希望额外的信息是有用的.

最佳答案 我不知道createJS足够,也不知道Flash Matrix对象,但是要使用原生Canvas2d API制作这种ovalGradient,您需要转换上下文的矩阵.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var horizontalScale = .3;
var verticalScale = 1;

var gradient = ctx.createRadialGradient(100/horizontalScale, 100/verticalScale, 100, 100/horizontalScale,100/verticalScale,0);
gradient.addColorStop(0,"green");
gradient.addColorStop(1,"red");

// shrink the context's matrix
ctx.scale(horizontalScale, verticalScale)
// draw your gradient
ctx.fillStyle = gradient;
// stretch the rectangle which contains the gradient accordingly
ctx.fillRect(0,0, 200/horizontalScale, 200/verticalScale);
// reset the context's matrix
ctx.setTransform(1,0,0,1,0,0);
canvas{ background-color: ivory;}
<canvas id="canvas" width="200" height="200"></canvas>

因此,如果您打算编写某种函数来重现它,请查看ctx.scale(),ctx.transform()ctx.setTransform().

编辑

正如你所注意到的,这也会缩小你绘制的形状,你也必须计算你应该在绘图中“解开”多少,就像我对fillRect一样. (同意,这个很容易)

这是一个可以帮助您处理更复杂形状的函数.我没有真正测试它(只有给定的例子),所以它可能以某种方式失败,但它也可以让你知道如何处理它:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

function shrinkedRadial(ctx, shapeArray, xScale, yScale, gradientOpts) {

    // scaling by 0 is like not drawing
    if (!xScale || !yScale) return;

    var gO = gradientOpts;
    // apply our scale on the gradient options we passed
    var gradient = ctx.createRadialGradient(gO.x0 / xScale, gO.y0 / yScale, gO.r0, gO.x1 / xScale, gO.y1 / yScale, gO.r1);
    gradient.addColorStop(gO.c1_pos, gO.c1_fill);
    gradient.addColorStop(gO.c2_pos, gO.c2_fill);

    // shrink the context's matrix
    ctx.scale(xScale, yScale);

    ctx.fillStyle = gradient;
    // execute the drawing operations' string
    shapeArray.forEach(function(str) {
      var val = str.split(' ');
      var op = shapesRef[val[0]];
      if (val[1]) {
        var pos = val[1].split(',').map(function(v, i) {
          // if even, it should be an y axis, otherwise an x one
          return i % 2 ? v / yScale : v / xScale;
        });
        ctx[op].apply(ctx, pos);
      } else {
        // no parameters
        ctx[op]();
      }
    });
    // apply our gradient
    ctx.fill();
    // reset the transform matrix
    ctx.setTransform(1, 0, 0, 1, 0, 0);
  }

// just for shortening our shape drawing operations
// notice how arc operations are omitted, it could be implemented but...
var shapesRef = {
  b: 'beginPath',
  fR: 'fillRect',
  m: 'moveTo',
  l: 'lineTo',
  bC: 'bezierCurveTo',
  qC: 'quadraticCurveTo',
  r: 'rect',
  c: 'closePath'
};

var gradientOpts = {
  x0: 232,
  y0: 55,
  r0: 70,
  x1: 232,
  y1: 55,
  r1: 0,
  c1_fill: 'red',
  c1_pos: 0,
  c2_fill: 'green',
  c2_pos: 1
}

var shapes = ['b', 'm 228,133', 'bC 209,121,154,76,183,43', 'bC 199,28,225,34,233,59', 'bC 239,34,270,29,280,39', 'bC 317,76,248,124,230,133']

// our shape is drawn at 150px from the right so we do move the context accordingly, but you won't have to.
ctx.translate(-150, 0);

shrinkedRadial(ctx, shapes, .3, 1, gradientOpts);

ctx.font = '15px sans-serif';
ctx.fillStyle = 'black';
ctx.fillText('shrinked radialGradient', 3, 20);

// how it looks like without scaling : 

ctx.translate(50, 0)

var gO = gradientOpts;
var gradient = ctx.createRadialGradient(gO.x0, gO.y0, gO.r0, gO.x1, gO.y1, gO.r1);
gradient.addColorStop(gO.c1_pos, gO.c1_fill);
gradient.addColorStop(gO.c2_pos, gO.c2_fill);

ctx.fillStyle = gradient;

shapes.forEach(function(str) {
  var val = str.split(' ');
  var op = shapesRef[val[0]];
  if (val[1]) {
    var pos = val[1].split(',');
    ctx[op].apply(ctx, pos);
  } else {
    ctx[op]();
  }
});
ctx.fill();
ctx.font = '15px sans-serif';
ctx.fillStyle = 'black';
ctx.fillText('normal radialGradient', 160, 20);
<canvas id="canvas" width="400" height="150"></canvas>
点赞