CreateJS径向渐变与矩阵

Posted

技术标签:

【中文标题】CreateJS径向渐变与矩阵【英文标题】:CreateJS Radial gradient with matrix 【发布时间】:2016-06-03 05:46:55 【问题描述】:

我正在将 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 )

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

任何帮助将不胜感激。

提前致谢

编辑

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

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

但是,它也可能显得拉伸,我认为这是矩阵的帮助。

我试图通过创建一个带有矩阵的 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 无法重现的矩阵制作的 AS3 渐变的视觉示例?显示您尝试过的代码,以便其他人可以看到您要去哪里... 【参考方案1】:

标准矩阵会按以下顺序调整输入:Width, angle Horizontal, angle Vertical, Height, pos X, pos Y

您在这里使用的是 gradientBox,这不是通常的 AS3 矩阵类型。预期输入:Width, Height, Rotation, pos X, pos Y

我不使用 createJS,所以我猜这个(你建立在它之上)...

你平时的beginRadialGradientFill(colors, ratios, x0, y0, r0, x1, y1, r1 )

变成如下(好像涉及到梯度框矩阵):beginRadialGradientFill(colors, ratios, posX, posY, Rotation, Width, Height, Rotation )

【讨论】:

我已尝试按照您的建议插入参数,但似乎无法正常工作。 html5/canvas 渐变是使用 2 个圆圈制作的,因此更改参数只会移动第二个圆圈的坐标 我现在从更新中看到,您还需要拉伸/挤压。你能不只是缩放画布绘制的渐变,然后将它叠加在另一个画布背景上作为最终输出吗?【参考方案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>

【讨论】:

抱歉格式化,我在用手机。这就是我目前正在研究的解决方案。然而,我在渐变中使用的形状非常复杂(想象一条线向下然后被向左或向右拖动,它代表气流条件)。如果我转换上下文,形状也会被转换,不是吗? 是的,你的形状也会被拉伸/收缩,所以你必须通过反转比例来绘制它,就像我对矩形所做的那样。显然,对于更复杂的形状,这将变得更加困难。 感谢您的出色回答,这对您有很大帮助。

以上是关于CreateJS径向渐变与矩阵的主要内容,如果未能解决你的问题,请参考以下文章

createjs使用雪碧图代码

Createjs学习一

createjs相关笔记

createjs开发教程

一篇文章带你快速入门createjs

CreateJS结合Falsh工具生成动画(加密字符串的由来)