@awayjs/graphics
Version:
AwayJS graphics classes
174 lines (156 loc) • 5.14 kB
text/typescript
import { ColorUtils, Matrix, Rectangle } from '@awayjs/core';
import { GradientType } from '../GradientType';
import { IFillStyle } from '../IGraphicsData';
export class GradientFillStyle implements IFillStyle {
public static data_type: string = '[graphicsdata GradientFillStyle]';
/**
* The Vector of drawing commands as integers representing the path.
*/
public colors: number[];
public colors_r: number[];
public colors_g: number[];
public colors_b: number[];
public alphas: number[];
public ratios: number[];
public ratio_min: number;
public ratio_max: number;
public type: GradientType;
public matrix: Matrix;
public spreadMethod: string;
public interpolationMethod: string;
public focalPointRatio: number;
public uvRectangle: Rectangle;
private _uvMatrix: Matrix;
constructor(
type: GradientType,
colors: number[],
alphas: number[],
ratios: number[],
matrix: Matrix,
spreadMethod: string,
interpolationMethod: string,
focalPointRatio: number
) {
if (colors.length != alphas.length || colors.length != ratios.length) {
throw ('GradientFillStyle: Error - colors, alphas and ratios must be of same length');
}
this.colors = colors;
this.colors_r = [];
this.colors_g = [];
this.colors_b = [];
this.colors_r.length = this.colors_g.length = this.colors_g.length = this.colors.length;
this.alphas = alphas;
this.ratios = ratios;
this.matrix = matrix;
this.type = type;
this.uvRectangle = new Rectangle();
this.ratios.sort((a, b) => a - b);
this.ratio_min = this.ratios[0];
this.ratio_max = this.ratios[this.ratios.length - 1];
// todo: in case the ratios.sort has changed the order of ratios,
// do we need to sync the order of color too ?
let c: number = colors.length;
let argb: number[];
while (c > 0) {
c--;
argb = ColorUtils.float32ColorToARGB(colors[c]);
this.colors_r[c] = argb[1];
this.colors_g[c] = argb[2];
this.colors_b[c] = argb[3];
}
}
public getUVMatrix(): Matrix {
if (this._uvMatrix) {
return this._uvMatrix;
}
if (!this.matrix) {
this.matrix = new Matrix();
}
const projection_width: number = 1638.4;
const projection_width_half: number = projection_width * 0.5;
// Get and invert the uv transform:
// not TRANSFORM already transformed matrix
const a: number = this.matrix.a;
const b: number = this.matrix.b;
const c: number = this.matrix.c;
const d: number = this.matrix.d;
const tx: number = this.matrix.tx;
const ty: number = this.matrix.ty;
const a_inv: number = d / (a * d - b * c);
const b_inv: number = -b / (a * d - b * c);
const c_inv: number = -c / (a * d - b * c);
const d_inv: number = a / (a * d - b * c);
const tx_inv: number = (c * ty - d * tx) / (a * d - b * c);
const ty_inv: number = -(a * ty - b * tx) / (a * d - b * c);
let resultMatrix: Matrix;
if (this.type == GradientType.LINEAR) {
resultMatrix = new Matrix(
(a_inv / projection_width) * (1 - (1 / 256)),
0,
(c_inv / projection_width) * (1 - (1 / 256)),
0,
(this.uvRectangle.x) + ((tx_inv + projection_width_half) / projection_width) * (1 - (1 / 256)),
this.uvRectangle.y);
} else if (this.type == GradientType.RADIAL) {
resultMatrix = new Matrix(
a_inv / projection_width_half,
b_inv / projection_width_half,
c_inv / projection_width_half,
d_inv / projection_width_half,
((tx_inv + projection_width_half) / projection_width_half) - 1,
((ty_inv + projection_width_half) / projection_width_half) - 1);
} else {
this._uvMatrix = this.matrix;
}
return this._uvMatrix = resultMatrix;
}
public getColorAtPosition(value: number): number[] {
let r1: number = -1;
let r2: number = -1;
if (value <= this.ratio_min) {
r1 = 0;
r2 = 0;
} else if (value >= this.ratio_max) {
r1 = this.ratios.length - 1;
r2 = this.ratios.length - 1;
} else {
for (let r: number = 0; r < this.ratios.length - 1;r++) {
if (value == this.ratios[r]) {
r1 = r;
r2 = r;
break;
} else if (value == this.ratios[r + 1]) {
r1 = r + 1;
r2 = r + 1;
break;
} else if (value >= this.ratios[r] && value <= this.ratios[r + 1]) {
r1 = r;
r2 = r + 1;
break;
}
}
}
if (r1 == r2) {
return [this.alphas[r1], this.colors_r[r1], this.colors_g[r1], this.colors_b[r1]];
}
const mix: number = (value - this.ratios[r1]) / (this.ratios[r2] - this.ratios[r1]);
const mix_neg: number = 1 - mix;
const color_a: number = this.alphas[r2] * mix + this.alphas[r1] * mix_neg;
const color_r: number = this.colors_r[r2] * mix + this.colors_r[r1] * mix_neg;
const color_g: number = this.colors_g[r2] * mix + this.colors_g[r1] * mix_neg;
const color_b: number = this.colors_b[r2] * mix + this.colors_b[r1] * mix_neg;
return [color_a, color_r, color_g, color_b];
}
public toString(): string {
let str: string = '';
let c: number = this.colors.length;
while (c > 0) {
c--;
str += this.colors[c] + '#' + this.alphas[c] + '#' + this.ratios[c] + '#';
}
return str;
}
public get data_type(): string {
return GradientFillStyle.data_type;
}
}