Graphics - bobby169/createjsDoc GitHub Wiki

Graphics

Graphics类公开了一个易于使用的API,用于生成矢量绘图指令并将它们绘制到指定的上下文。请注意,您可以通过调用graphics/draw来使用图形,而不依赖于easeljs框架。或者直接与Shape对象一起使用,在EaselJS显示列表的上下文上绘制矢量图形。

使用Graphics类有两种方法

  1. 先实例化Graphics类,再调用实例中的方法
  2. new Graphics().command,用Graphics/append将其添加到graphics队列中。

前者抽象后者,简化开始和结束路径、填充和笔画。

var g = new createjs.Graphics();
g.setStrokeStyle(1);
g.beginStroke("#000000");
g.beginFill("red");
g.drawCircle(0,0,30);

所有的绘图方法,都返回Graphics实例,因此方向可以用链式写法。例如,

myGraphics.beginStroke("red").beginFill("blue").drawRect(20, 20, 100, 50);

每个graphics API方法都会生成一个command object

var fillCommand = myGraphics.beginFill("red").command;
// ... later, update the fill style/color:
fillCommand.style = "blue";
// or change it to a bitmap fill:
fillCommand.bitmap(myImage);

为了更直接地控制渲染,可以直接实例化command objects并将其附加到图形队列中。在这种情况下,你需要手动管理路径创建,并确保将fill/stroke应用于定义的路径:

// start a new path. Graphics.beginCmd is a reusable BeginPath instance:
myGraphics.append(createjs.Graphics.beginCmd);
// we need to define the path before applying the fill:
var circle = new createjs.Graphics.Circle(0,0,30);
myGraphics.append(circle);
// fill the path we just defined:
var fill = new createjs.Graphics.Fill("red");
myGraphics.append(fill);

这些方法可以一起使用,例如插入自定义命令:

myGraphics.beginFill("red");
var customCommand = new CustomSpiralCommand(etc);
myGraphics.append(customCommand);
myGraphics.beginFill("blue");
myGraphics.drawCircle(0, 0, 30);

draw()

// 将显示对象绘制到指定的上下文中,忽略其可见、alpha、阴影和转换。
// 如果处理了绘图,则返回true(对于重写功能很有用)。

p.draw = function(ctx, data) {
  this._updateInstructions();
  var instr = this._instructions; // 当前需要绘制的图形命令
  for (var i=this._storeIndex, l=instr.length; i<l; i++) {
    // 执行command exec命令
    instr[i].exec(ctx, data);
  }
};

Graphics类没有继承DisplayObject类,其中的draw()方法不会被执行,要执行其中的draw()怎么办呢? 就必须用到Shape类,因为Shape类继承了DisplayObject类,会自动执行其draw()方法。再内部调用Graphics类中的draw()方法

// Shape类
p.draw = function(ctx, ignoreCache) {
    if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
    this.graphics.draw(ctx, this); // 执行graphics实例中的draw方法
    return true;
};

command

保留对上一个已创建或附加的命令的引用。例如,可以保留对fill命令的引用,以便以后使用以下命令动态更新颜色:

var myFill = myGraphics.beginFill("red").command;
// update color later:
myFill.style = "yellow";

append()

@param {Object} command: 一个graphics command object,其有exec方法
@param {boolean} clean: 清除参数主要用于内部使用。如果值为true,则表示`stroked` 或 `filled`的时候,command不会生成path。
p.append = function(command, clean) {
    // 把command push到当前指令数组中(Uncommitted instructions)
    this._activeInstructions.push(command);

    // 这里非常重要,每次append的时候,把当前command引用保存到graphics.command。就可以直接操作graphics.command了
    this.command = command;

    if (!clean) { this._dirty = true; }
    return this;
};

command长什么样子?我们先看一下moveTo方法

p.moveTo = function(x, y) {
  return this.append(new G.MoveTo(x,y), true);
};
// 这里的`new G.MoveTo(x,y)`就是一个command

(G.MoveTo = function(x, y) {
    this.x = x; this.y = y;
}).prototype.exec = function(ctx) { ctx.moveTo(this.x, this.y); };
// command实例必有一个exec方法
// 比如操作command,就相当于操作G.MoveTo()实例对象
// 每次draw时都会调用command的exec方向,操作当前的context进行真正的图形绘制

beginFill/f(color) 填充颜色

使用指定的颜色开始填充。这将结束当前子路径。

p.beginFill = function(color) {
    return this._setFill(color ? new G.Fill(color) : null);
};

p = (G.Fill = function(style, matrix) {
    this.style = style;
    this.matrix = matrix;
}).prototype;
p.exec = function(ctx) {
    if (!this.style) { return; }
    ctx.fillStyle = this.style;
    var mtx = this.matrix;
    if (mtx) { ctx.save(); ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty); }
    ctx.fill(); // 非常重要
    if (mtx) { ctx.restore(); }
};
// 画个圆,用红色填充
let shape = new createjs.Shape()
shape.graphics.beginFill('red').drawCircle(0, 0, 100)

beginStroke/s(color) 边框颜色

以指定的颜色开始笔划。这将结束当前子路径。

p.beginStroke = function(color) {
    return this._setStroke(color ? new G.Stroke(color) : null);
};

p = (G.Stroke = function(style, ignoreScale) {
    this.style = style;
    this.ignoreScale = ignoreScale;
}).prototype;
p.exec = function(ctx) {
    if (!this.style) { return; }
    ctx.strokeStyle = this.style;
    if (this.ignoreScale) { ctx.save(); ctx.setTransform(1,0,0,1,0,0); }
    ctx.stroke(); // 非常重要
    if (this.ignoreScale) { ctx.restore(); }
};
// 画条线
let shape = new createjs.Shape()
shape.graphics.beginStroke(color).setStrokeStyle(width, 'butt', 'miter').moveTo(x1, y1).lineTo(x2, y2)

思考?上面代码,我们在画一条线段的时候,在结尾并没有执行stroke()方法,但是用原生canvas绘图,前面的moveTo,lineTo是绘制path。最后一定要执行stroke()才是真正的绘制。然后上面的代码并没有执行stroke()方法,为什么呢?

原来在执行beginStroke(color)的时候,就会调用 new G.Stroke(color),其中就有ctx.stroke()

endFill/ef()

结束当前子路径,并开始一个没有填充的新路径。功能上与beginfill(null)相同。

p.endFill = function() {
    return this.beginFill();
};

endStroke/es()

结束当前子路径,并开始一个没有笔画的新路径。功能上与beginstroke(null)相同。

p.endStroke = function() {
    return this.beginStroke();
};
let star = new createjs.Shape()
star.graphics.setStrokeStyle(1).beginStroke(createjs.Graphics.getRGB(255, 255, 0)).beginFill('#FF0').endStroke().drawPolyStar(0, 0, 80, 5, 0.6, -90)
[caps=0] butt, round, or square. Defaults to "butt"
[joints=0] bevel, round, or miter. Defaults to "miter"
[miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which controls at what point a mitered joint will be clipped.
[ignoreScale=false] 如果为true,则不管活动转换如何,都将以指定的厚度绘制笔划。

setStrokeStyle(thickness [caps=0] [joints=0] [miterLimit=10] [ignoreScale=false] )

设置笔划样式。因此可以在一行代码中定义笔划样式和颜色,如:

myGraphics.setStrokeStyle(8,"round").beginStroke("#F00");
p = (G.StrokeStyle = function(width, caps, joints, miterLimit, ignoreScale) {
    this.width = width;
    this.caps = caps;
    this.joints = joints;
    this.miterLimit = miterLimit;
    this.ignoreScale = ignoreScale;
}).prototype;
p.exec = function(ctx) {
    ctx.lineWidth = (this.width == null ? "1" : this.width);
    ctx.lineCap = (this.caps == null ? "butt" : (isNaN(this.caps) ? this.caps : Graphics.STROKE_CAPS_MAP[this.caps]));
    ctx.lineJoin = (this.joints == null ? "miter" : (isNaN(this.joints) ? this.joints : Graphics.STROKE_JOINTS_MAP[this.joints]));
    ctx.miterLimit = (this.miterLimit == null ? "10" : this.miterLimit);
    ctx.ignoreScale = (this.ignoreScale == null ? false : this.ignoreScale);
};
[segments] Array 指定虚线图案的数组,在线条和间隙之间交替。例如,[20,10]将创建一个由20个像素线组成的图案,它们之间有10个像素间隔。传递空数组或空数组将清除现有的笔划短划线。
[offset=0] 虚线图案的偏移offset

setStrokeDash( [segments] [offset=0] )

var dashCmd;
var game = new hb.Game({
},{
    create:function () {
        var shape = new createjs.Shape();
        game.stage.addChild(shape);

        // set a stroke dash, and save the command object:
        dashCmd = shape.graphics.setStrokeDash([10,5]).command;
        // draw a couple of rectangles with the stroke dash:
        shape.graphics.setStrokeStyle(2).beginStroke("black").rect(20,20,100,100);
        // this rectangle is drawn backwards, which will reverse the direction of the effect:
        shape.graphics.setStrokeStyle(10).beginStroke("blue").rect(240,20,-100,100);

        // reset the stroke dash, and draw a red rectangle:
        shape.graphics.setStrokeDash();
        shape.graphics.setStrokeStyle(4).beginStroke("red").rect(260,20,100,100);

        // dotted dash:
        shape.graphics.setStrokeDash([2,2]);
        shape.graphics.setStrokeStyle(2).beginStroke("green").rect(380,20,100,100);
    },
    update:function () {
        // increment the offset to animate the marching ants:
        dashCmd.offset++;
    }
})

closePath/cp()

p.closePath = function() {
    return this._activeInstructions.length ? this.append(new G.ClosePath()) : this;
};

(G.ClosePath = function() {
}).prototype.exec = function(ctx) { ctx.closePath(); };

clear/c()

清除所有绘图命令,有效地重置此Graphics instance。任何线条和填充样式都需要重新定义才能在明确的调用后绘制形状。

p.clear = function() {
    this._instructions.length = this._activeInstructions.length = this._commitIndex = 0;
    this._strokeStyle = this._oldStrokeStyle = this._stroke = this._fill = this._strokeDash = this._oldStrokeDash = null;
    this._dirty = this._strokeIgnoreScale = false;
    return this;
};

decodePath/p(str)

将压缩编码的路径字符串解码为一系列绘图指令。此格式不是供人阅读的,而是供创作工具使用的。该格式使用base64字符集(每个字符代表6位)定义一系列绘图命令。

如Adobe AN生成的进行解码绘图指令

this.shape_64 = new cjs.Shape();
this.shape_64.graphics.f("#573E24").s().p("AgTBBQgSgCgCgSIAAhZQACgSASgCIAnAAQASACACASIAABZQgCASgSACg");
this.shape_64.setTransform(-97.3,-20.1);