PixiJS 图形绘制 #

Graphics 概述 #

Graphics 是 PixiJS 中用于绘制矢量图形的类,它提供了一套简单易用的 API 来创建各种形状。

text
┌─────────────────────────────────────────────────────────────┐
│                    Graphics 功能                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   基本形状                                                  │
│   ├── 矩形 (rect)                                          │
│   ├── 圆角矩形 (roundRect)                                  │
│   ├── 圆形 (circle)                                        │
│   └── 椭圆 (ellipse)                                       │
│                                                             │
│   复杂形状                                                  │
│   ├── 多边形 (poly)                                        │
│   ├── 路径 (moveTo, lineTo)                                │
│   └── 弧线 (arc, arcTo)                                    │
│                                                             │
│   样式设置                                                  │
│   ├── 填充 (fill)                                          │
│   ├── 描边 (stroke)                                        │
│   └── 线条样式                                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

创建 Graphics #

基本创建 #

javascript
import { Graphics } from 'pixi.js';

const graphics = new Graphics();
app.stage.addChild(graphics);

绘制流程 #

text
┌─────────────────────────────────────────────────────────────┐
│                    绘制流程                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   1. 清除(可选)                                           │
│      graphics.clear()                                       │
│                                                             │
│   2. 定义形状                                               │
│      graphics.rect(0, 0, 100, 100)                         │
│                                                             │
│   3. 设置样式                                               │
│      graphics.fill({ color: 0xff0000 })                    │
│                                                             │
│   4. 添加到舞台                                             │
│      app.stage.addChild(graphics)                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

基本形状 #

矩形 #

javascript
const graphics = new Graphics();

// 基本矩形
graphics.rect(50, 50, 100, 80);
graphics.fill({ color: 0xff0000 });

// 圆角矩形
graphics.roundRect(200, 50, 100, 80, 10);
graphics.fill({ color: 0x00ff00 });

// 多个矩形
graphics.rect(50, 200, 50, 50);
graphics.rect(120, 200, 50, 50);
graphics.rect(190, 200, 50, 50);
graphics.fill({ color: 0x0000ff });

app.stage.addChild(graphics);

圆形 #

javascript
const graphics = new Graphics();

// 基本圆形
graphics.circle(100, 100, 50);
graphics.fill({ color: 0xff0000 });

// 圆形描边
graphics.circle(250, 100, 50);
graphics.stroke({ width: 3, color: 0x00ff00 });

// 多个圆形
for (let i = 0; i < 5; i++) {
  graphics.circle(100 + i * 80, 250, 30);
  graphics.fill({ color: 0x0000ff + i * 0x001100 });
}

app.stage.addChild(graphics);

椭圆 #

javascript
const graphics = new Graphics();

// 基本椭圆
graphics.ellipse(150, 100, 80, 50);
graphics.fill({ color: 0xff9900 });

// 垂直椭圆
graphics.ellipse(350, 100, 50, 80);
graphics.fill({ color: 0x0099ff });

app.stage.addChild(graphics);

多边形 #

javascript
const graphics = new Graphics();

// 三角形
graphics.poly([100, 50, 150, 150, 50, 150]);
graphics.fill({ color: 0xff0000 });

// 五边形
const sides = 5;
const radius = 50;
const centerX = 300;
const centerY = 100;
const points = [];

for (let i = 0; i < sides; i++) {
  const angle = (i / sides) * Math.PI * 2 - Math.PI / 2;
  points.push(
    centerX + Math.cos(angle) * radius,
    centerY + Math.sin(angle) * radius
  );
}

graphics.poly(points);
graphics.fill({ color: 0x00ff00 });

// 星形
graphics.star(500, 100, 5, 50, 25);
graphics.fill({ color: 0xffff00 });

app.stage.addChild(graphics);

路径绘制 #

基本路径 #

javascript
const graphics = new Graphics();

// 移动起点
graphics.moveTo(50, 50);

// 画线到点
graphics.lineTo(150, 50);
graphics.lineTo(150, 150);
graphics.lineTo(50, 150);

// 闭合路径
graphics.closePath();

// 描边
graphics.stroke({ width: 2, color: 0xff0000 });

app.stage.addChild(graphics);

复杂路径 #

javascript
const graphics = new Graphics();

// 绘制箭头
graphics.moveTo(100, 50);
graphics.lineTo(150, 100);
graphics.lineTo(125, 100);
graphics.lineTo(125, 150);
graphics.lineTo(75, 150);
graphics.lineTo(75, 100);
graphics.lineTo(50, 100);
graphics.closePath();
graphics.fill({ color: 0x3366ff });

app.stage.addChild(graphics);

弧线 #

javascript
const graphics = new Graphics();

// 圆弧
graphics.arc(100, 100, 50, 0, Math.PI);
graphics.stroke({ width: 2, color: 0xff0000 });

// 完整圆
graphics.arc(250, 100, 50, 0, Math.PI * 2);
graphics.stroke({ width: 2, color: 0x00ff00 });

// 弧形填充(饼图效果)
graphics.moveTo(400, 100);
graphics.arc(400, 100, 50, 0, Math.PI * 1.5);
graphics.closePath();
graphics.fill({ color: 0x0000ff });

app.stage.addChild(graphics);

样式设置 #

填充样式 #

javascript
const graphics = new Graphics();

// 纯色填充
graphics.rect(50, 50, 80, 60);
graphics.fill({ color: 0xff0000 });

// 带透明度的填充
graphics.rect(150, 50, 80, 60);
graphics.fill({ color: 0x00ff00, alpha: 0.5 });

// 渐变填充(需要使用 Texture)
const gradientTexture = createGradientTexture();
graphics.rect(250, 50, 80, 60);
graphics.fill({ texture: gradientTexture });

app.stage.addChild(graphics);

描边样式 #

javascript
const graphics = new Graphics();

// 基本描边
graphics.rect(50, 50, 80, 60);
graphics.stroke({ width: 2, color: 0xff0000 });

// 粗描边
graphics.rect(150, 50, 80, 60);
graphics.stroke({ width: 5, color: 0x00ff00 });

// 带透明度的描边
graphics.rect(250, 50, 80, 60);
graphics.stroke({ width: 3, color: 0x0000ff, alpha: 0.5 });

app.stage.addChild(graphics);

线条端点和连接 #

javascript
const graphics = new Graphics();

// 设置线条样式
graphics.rect(50, 50, 80, 60);
graphics.stroke({
  width: 10,
  color: 0xff0000,
  alpha: 1,
  alignment: 0.5,  // 0-1,线条对齐方式
  native: false    // 是否使用原生线条
});

app.stage.addChild(graphics);

填充与描边组合 #

同时填充和描边 #

javascript
const graphics = new Graphics();

// 先填充后描边
graphics.circle(100, 100, 50);
graphics.fill({ color: 0xff9900 });
graphics.stroke({ width: 3, color: 0xff0000 });

// 多个形状
graphics.rect(200, 50, 100, 100);
graphics.fill({ color: 0x00ff00 });
graphics.stroke({ width: 2, color: 0x006600 });

app.stage.addChild(graphics);

分开绘制 #

javascript
const graphics = new Graphics();

// 填充形状
graphics.circle(100, 100, 50);
graphics.fill({ color: 0xff9900 });

// 描边形状(需要新路径)
graphics.circle(100, 100, 50);
graphics.stroke({ width: 3, color: 0xff0000 });

app.stage.addChild(graphics);

清除和重绘 #

清除图形 #

javascript
const graphics = new Graphics();

// 清除所有图形
graphics.clear();

// 清除后重新绘制
graphics.rect(50, 50, 100, 100);
graphics.fill({ color: 0xff0000 });

动态更新 #

javascript
const graphics = new Graphics();
app.stage.addChild(graphics);

let angle = 0;

app.ticker.add(() => {
  graphics.clear();
  
  // 绘制旋转的矩形
  graphics.rect(-50, -50, 100, 100);
  graphics.fill({ color: 0xff0000 });
  
  graphics.rotation = angle;
  graphics.position.set(400, 300);
  
  angle += 0.01;
});

高级技巧 #

绘制网格 #

javascript
function drawGrid(graphics, width, height, cellSize, color) {
  graphics.clear();
  
  // 垂直线
  for (let x = 0; x <= width; x += cellSize) {
    graphics.moveTo(x, 0);
    graphics.lineTo(x, height);
  }
  
  // 水平线
  for (let y = 0; y <= height; y += cellSize) {
    graphics.moveTo(0, y);
    graphics.lineTo(width, y);
  }
  
  graphics.stroke({ width: 1, color, alpha: 0.3 });
  
  return graphics;
}

const grid = drawGrid(new Graphics(), 800, 600, 50, 0xffffff);
app.stage.addChild(grid);

绘制圆环 #

javascript
function drawRing(graphics, x, y, innerRadius, outerRadius, color) {
  graphics.clear();
  
  // 外圆
  graphics.circle(x, y, outerRadius);
  graphics.fill({ color });
  
  // 内圆(镂空)
  graphics.circle(x, y, innerRadius);
  graphics.fill({ color: 0x000000, alpha: 0 });
  
  return graphics;
}

const ring = drawRing(new Graphics(), 400, 300, 40, 60, 0xff9900);
app.stage.addChild(ring);

绘制进度条 #

javascript
class ProgressBar extends Graphics {
  constructor(width, height, backgroundColor, fillColor) {
    super();
    this.barWidth = width;
    this.barHeight = height;
    this.backgroundColor = backgroundColor;
    this.fillColor = fillColor;
    this._progress = 0;
    
    this.draw();
  }
  
  get progress() {
    return this._progress;
  }
  
  set progress(value) {
    this._progress = Math.max(0, Math.min(1, value));
    this.draw();
  }
  
  draw() {
    this.clear();
    
    // 背景
    this.roundRect(0, 0, this.barWidth, this.barHeight, 5);
    this.fill({ color: this.backgroundColor });
    
    // 进度
    if (this._progress > 0) {
      const fillWidth = this.barWidth * this._progress;
      this.roundRect(0, 0, fillWidth, this.barHeight, 5);
      this.fill({ color: this.fillColor });
    }
  }
}

const progressBar = new ProgressBar(300, 30, 0x333333, 0x00ff00);
progressBar.x = 250;
progressBar.y = 300;
app.stage.addChild(progressBar);

// 更新进度
progressBar.progress = 0.75;

绘制图表 #

javascript
function drawBarChart(data, x, y, width, height) {
  const graphics = new Graphics();
  
  const maxValue = Math.max(...data.map(d => d.value));
  const barWidth = width / data.length - 10;
  
  data.forEach((item, index) => {
    const barHeight = (item.value / maxValue) * height;
    const barX = x + index * (barWidth + 10);
    const barY = y + height - barHeight;
    
    graphics.rect(barX, barY, barWidth, barHeight);
    graphics.fill({ color: item.color });
  });
  
  return graphics;
}

const chart = drawBarChart([
  { value: 100, color: 0xff0000 },
  { value: 200, color: 0x00ff00 },
  { value: 150, color: 0x0000ff },
  { value: 180, color: 0xffff00 }
], 100, 100, 400, 200);

app.stage.addChild(chart);

绘制雷达图 #

javascript
function drawRadarChart(centerX, centerY, radius, values, labels) {
  const graphics = new Graphics();
  const sides = values.length;
  const angleStep = (Math.PI * 2) / sides;
  
  // 绘制背景网格
  for (let r = 0.2; r <= 1; r += 0.2) {
    const points = [];
    for (let i = 0; i < sides; i++) {
      const angle = angleStep * i - Math.PI / 2;
      points.push(
        centerX + Math.cos(angle) * radius * r,
        centerY + Math.sin(angle) * radius * r
      );
    }
    graphics.poly(points);
    graphics.stroke({ width: 1, color: 0x666666, alpha: 0.5 });
  }
  
  // 绘制轴线
  for (let i = 0; i < sides; i++) {
    const angle = angleStep * i - Math.PI / 2;
    graphics.moveTo(centerX, centerY);
    graphics.lineTo(
      centerX + Math.cos(angle) * radius,
      centerY + Math.sin(angle) * radius
    );
  }
  graphics.stroke({ width: 1, color: 0x666666, alpha: 0.5 });
  
  // 绘制数据区域
  const dataPoints = [];
  for (let i = 0; i < sides; i++) {
    const angle = angleStep * i - Math.PI / 2;
    const value = values[i] / 100;
    dataPoints.push(
      centerX + Math.cos(angle) * radius * value,
      centerY + Math.sin(angle) * radius * value
    );
  }
  
  graphics.poly(dataPoints);
  graphics.fill({ color: 0x00ff00, alpha: 0.3 });
  graphics.stroke({ width: 2, color: 0x00ff00 });
  
  return graphics;
}

const radar = drawRadarChart(400, 300, 150, [80, 60, 90, 70, 85], []);
app.stage.addChild(radar);

性能优化 #

使用 Graphics 缓存 #

javascript
const graphics = new Graphics();

// 绘制复杂图形
graphics.rect(0, 0, 100, 100);
graphics.fill({ color: 0xff0000 });

// 缓存为位图
graphics.cacheAsBitmap = true;

// 这将提高渲染性能,但会增加内存使用

批量绘制 #

javascript
// 不推荐:多次绘制
for (let i = 0; i < 100; i++) {
  const g = new Graphics();
  g.circle(Math.random() * 800, Math.random() * 600, 5);
  g.fill({ color: 0xff0000 });
  app.stage.addChild(g);
}

// 推荐:单个 Graphics 绘制多个形状
const graphics = new Graphics();
for (let i = 0; i < 100; i++) {
  graphics.circle(Math.random() * 800, Math.random() * 600, 5);
}
graphics.fill({ color: 0xff0000 });
app.stage.addChild(graphics);

避免频繁清除 #

javascript
// 不推荐:每帧清除重绘
app.ticker.add(() => {
  graphics.clear();
  graphics.circle(x, y, 50);
  graphics.fill({ color: 0xff0000 });
});

// 推荐:使用变换而非重绘
const circle = new Graphics();
circle.circle(0, 0, 50);
circle.fill({ color: 0xff0000 });
app.stage.addChild(circle);

app.ticker.add(() => {
  circle.position.set(x, y);
});

实战示例 #

绘制按钮 #

javascript
class Button extends Graphics {
  constructor(text, width = 150, height = 50) {
    super();
    this.buttonWidth = width;
    this.buttonHeight = height;
    this.text = text;
    this.isHovered = false;
    
    this.eventMode = 'static';
    this.cursor = 'pointer';
    
    this.on('pointerover', () => this.onHover(true));
    this.on('pointerout', () => this.onHover(false));
    
    this.draw();
  }
  
  onHover(hovered) {
    this.isHovered = hovered;
    this.draw();
  }
  
  draw() {
    this.clear();
    
    const bgColor = this.isHovered ? 0x4488ff : 0x3366cc;
    
    this.roundRect(0, 0, this.buttonWidth, this.buttonHeight, 8);
    this.fill({ color: bgColor });
    
    // 添加文字需要单独的 Text 对象
  }
}

const button = new Button('Click Me');
button.x = 325;
button.y = 275;
app.stage.addChild(button);

绘制仪表盘 #

javascript
class Gauge extends Graphics {
  constructor(radius, minValue, maxValue) {
    super();
    this.radius = radius;
    this.minValue = minValue;
    this.maxValue = maxValue;
    this._value = minValue;
    
    this.draw();
  }
  
  get value() {
    return this._value;
  }
  
  set value(val) {
    this._value = Math.max(this.minValue, Math.min(this.maxValue, val));
    this.draw();
  }
  
  draw() {
    this.clear();
    
    // 背景弧
    this.arc(0, 0, this.radius, Math.PI * 0.75, Math.PI * 2.25);
    this.stroke({ width: 20, color: 0x333333 });
    
    // 值弧
    const progress = (this._value - this.minValue) / (this.maxValue - this.minValue);
    const endAngle = Math.PI * 0.75 + progress * Math.PI * 1.5;
    
    this.arc(0, 0, this.radius, Math.PI * 0.75, endAngle);
    this.stroke({ width: 20, color: 0x00ff00 });
  }
}

const gauge = new Gauge(80, 0, 100);
gauge.position.set(400, 300);
gauge.value = 75;
app.stage.addChild(gauge);

下一步 #

掌握了图形绘制后,接下来学习 文本处理,了解如何在 PixiJS 中渲染和样式化文本!

最后更新:2026-03-29