Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pixi.js - Draw Rectangle with Gradient Fill

I'm using the Pixi.js v4 graphics library to make a game with JavaScript. I know that I can draw a black + rounded rectangle like so:

const rectangle = new pixi.Graphics();
rectangle.beginFill(0); // Color it black
rectangle.drawRoundedRect(
    0,
    0,
    100, // Make it 100x100
    100,
    5, // Make the rounded corners have a radius of 5
);
rectangle.endFill();
stage.addChild(rectangle);
  1. How do I draw a rounded rectangle with a gradient from white to black?

  2. How do I draw a rounded rectangle that has gradual opacity such that it fades in from left to right?

like image 864
James Avatar asked Dec 18 '22 01:12

James


1 Answers

It looks like it's not possible to implement what you need with pixi.js without additional code, but we can do some magic to make it happen. Here's the result of what I've got: https://jsfiddle.net/exkf3zfo/21/

The bottom color is a pure red with 0.2 alpha.

I would split the whole process to the next steps:

  1. Drawing the gradient
  2. Masking the gradient with the rounded mask

Here is the code itself:

var app = new PIXI.Application(800, 600, {
  antialias: true
});
document.body.appendChild(app.view);

// Functions

// param color is a number (e.g. 255)
// return value is a string (e.g. ff)
var prepareRGBChannelColor = function(channelColor) {
  var colorText = channelColor.toString(16);
  if (colorText.length < 2) {
    while (colorText.length < 2) {
      colorText = "0" + colorText;
    }
  }

  return colorText;
}

// Getting RGB channels from a number color
// param color is a number
// return an RGB channels object {red: number, green: number, blue: number}
var getRGBChannels = function(color) {
  var colorText = color.toString(16);
  if (colorText.length < 6) {
    while (colorText.length < 6) {
      colorText = "0" + colorText;
    }
  }

  var result = {
    red: parseInt(colorText.slice(0, 2), 16),
    green: parseInt(colorText.slice(2, 4), 16),
    blue: parseInt(colorText.slice(4, 6), 16)
  };
  return result;
}

// Preparaiton of a color data object
// param color is a number [0-255]
// param alpha is a number [0-1]
// return the color data object {color: number, alpha: number, channels: {red: number, green: number, blue: number}}
var prepareColorData = function(color, alpha) {
  return {
    color: color,
    alpha: alpha,
    channels: getRGBChannels(color)
  }
}

// Getting the color of a gradient for a very specific gradient coef
// param from is a color data object
// param to is a color data object
// return value is of the same type
var getColorOfGradient = function(from, to, coef) {
  if (!from.alpha && from.alpha !== 0) {
    from.alpha = 1;
  }
  if (!from.alpha && from.alpha !== 0) {
    to.alpha = 1;
  }

  var colorRed = Math.floor(from.channels.red + coef * (to.channels.red - from.channels.red));
  colorRed = Math.min(colorRed, 255);
  var colorGreen = Math.floor(from.channels.green + coef * (to.channels.green - from.channels.green));
  colorGreen = Math.min(colorGreen, 255);
  var colorBlue = Math.floor(from.channels.blue + coef * (to.channels.blue - from.channels.blue));
  colorBlue = Math.min(colorBlue, 255);

  var rgb = prepareRGBChannelColor(colorRed) + prepareRGBChannelColor(colorGreen) + prepareRGBChannelColor(colorBlue);

  return {
    color: parseInt(rgb, 16),
    alpha: from.alpha + coef * (to.alpha - from.alpha)
  };
}

var startTime = Date.now();
console.log("start: " + startTime);

// Drawing the gradient
//
var gradient = new PIXI.Graphics();
app.stage.addChild(gradient);
//
var rect = {
  width: 200,
  height: 200
};
var round = 20;
//
var colorFromData = prepareColorData(0xFF00FF, 1);
var colorToData = prepareColorData(0xFF0000, 0.2);
//
var stepCoef;
var stepColor;
var stepAlpha;
var stepsCount = 100;
var stepHeight = rect.height / stepsCount;
for (var stepIndex = 0; stepIndex < stepsCount; stepIndex++) {
  stepCoef = stepIndex / stepsCount;
  stepColor = getColorOfGradient(colorFromData, colorToData, stepCoef);

  gradient.beginFill(stepColor.color, stepColor.alpha);
  gradient.drawRect(
    0,
    rect.height * stepCoef,
    rect.width,
    stepHeight
  );
}

// Applying a mask with round corners to the gradient
var roundMask = new PIXI.Graphics();
roundMask.beginFill(0x000000);
roundMask.drawRoundedRect(0, 0, rect.width, rect.height, round);
app.stage.addChild(roundMask);
gradient.mask = roundMask;

var endTime = Date.now();
console.log("end: " + endTime);
console.log("total: " + (endTime - startTime));

The interesting thing is that it takes only about 2-5 ms for the whole process!

If you wan't to change colors of the gradient to white>black (as described in the question), just change the next params:

var colorFromData = prepareColorData(0xFF00FF, 1);
var colorToData = prepareColorData(0xFF0000, 0.2);

To:

var colorFromData = prepareColorData(0xFFFFFF, 1);
var colorToData = prepareColorData(0x000000, 0.2);
like image 58
Mark Dolbyrev Avatar answered Dec 27 '22 04:12

Mark Dolbyrev