feat: graphics
This commit is contained in:
parent
86b5d7260c
commit
f22ea42b54
50
packages/graphics/color.js
Normal file
50
packages/graphics/color.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import {compose} from '@avocado/core';
|
||||
|
||||
import {Property} from '@avocado/mixins';
|
||||
|
||||
const decorate = compose(
|
||||
Property('red'),
|
||||
Property('green'),
|
||||
Property('blue'),
|
||||
Property('alpha'),
|
||||
)
|
||||
|
||||
export class Color {
|
||||
|
||||
static fromCss(css) {
|
||||
if ('#'.charCodeAt(0) === css.charCodeAt(0)) {
|
||||
let hex = css.substr(1);
|
||||
if (3 === hex.length) {
|
||||
hex = hex.split('').map((c) => c + c).join('');
|
||||
}
|
||||
const red = parseInt(hex.substr(0, 2), 16);
|
||||
const green = parseInt(hex.substr(2, 2), 16);
|
||||
const blue = parseInt(hex.substr(4, 2), 16);
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
else {
|
||||
const colors = css.replace(
|
||||
/\s/g, ''
|
||||
).match(
|
||||
/rgba?\((.*)\)/
|
||||
)[1].split(',');
|
||||
return new Color(colors[0], colors[1], colors[2], colors[3] || 1);
|
||||
}
|
||||
}
|
||||
|
||||
constructor(red = 255, green = 0, blue = 255, alpha = 1) {
|
||||
this.red = red;
|
||||
this.green = green;
|
||||
this.blue = blue;
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
toCss() {
|
||||
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
|
||||
}
|
||||
|
||||
toInteger() {
|
||||
return (this.red << 16) | (this.green << 8) | this.blue;
|
||||
}
|
||||
|
||||
}
|
37
packages/graphics/container.js
Normal file
37
packages/graphics/container.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
|
||||
|
||||
import {Renderable} from './renderable';
|
||||
|
||||
export class Container extends Renderable {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._children = [];
|
||||
this.internal = PIXI ? new PIXI.Container() : undefined;
|
||||
}
|
||||
|
||||
addChild(child) {
|
||||
this._children.push(child);
|
||||
this.internal.addChild(child.internal);
|
||||
}
|
||||
|
||||
children() {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
removeChild(child) {
|
||||
const index = this._children.indexOf(child);
|
||||
if (-1 === index) {
|
||||
return;
|
||||
}
|
||||
this._children.splice(index, 1);
|
||||
this.internal.removeChild(child.internal);
|
||||
}
|
||||
|
||||
removeAllChildren() {
|
||||
for (const child of this._children) {
|
||||
this.removeChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
|
||||
|
||||
import {Resource} from '@avocado/resource';
|
||||
|
||||
const baseTextureCache = {};
|
||||
|
||||
export class Image extends Resource {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.texture = null;
|
||||
}
|
||||
|
||||
static load(uri) {
|
||||
return this.loadBaseTexture(uri).then((baseTexture) => {
|
||||
const image = new Image();
|
||||
image.uri = uri;
|
||||
image.texture = new PIXI.Texture(baseTexture);
|
||||
return image;
|
||||
});
|
||||
}
|
||||
|
||||
static loadBaseTexture(uri) {
|
||||
if (baseTextureCache[uri]) {
|
||||
return Promise.resolve(baseTextureCache[uri]);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const baseTexture = PIXI.BaseTexture.fromImage(uri);
|
||||
baseTexture.on('error', () => {
|
||||
reject(new Error(`Couldn't load image "${uri}"`));
|
||||
});
|
||||
baseTexture.on('loaded', () => {
|
||||
resolve(baseTextureCache[uri] = baseTexture);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get height() {
|
||||
if (!this.texture) {
|
||||
return 0;
|
||||
}
|
||||
return this.texture.height;
|
||||
}
|
||||
|
||||
get size() {
|
||||
return [this.width, this.height];
|
||||
}
|
||||
|
||||
get width() {
|
||||
if (!this.texture) {
|
||||
return 0;
|
||||
}
|
||||
return this.texture.width;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export {Color} from './color';
|
||||
export {Container} from './container';
|
||||
export {Image} from './image';
|
||||
export {Primitives} from './primitives';
|
||||
export {Renderable} from './renderable';
|
||||
export {Renderer} from './renderer';
|
||||
export {Sprite} from './sprite';
|
|
@ -8,7 +8,9 @@
|
|||
"@avocado/core": "1.x",
|
||||
"@avocado/math": "1.x",
|
||||
"@avocado/mixins": "1.x",
|
||||
"@avocado/resource": "1.x",
|
||||
"debug": "^3.1.0",
|
||||
"immutable": "4.0.0-rc.12"
|
||||
"immutable": "4.0.0-rc.12",
|
||||
"pixi.js": "4.8.6"
|
||||
}
|
||||
}
|
||||
|
|
67
packages/graphics/primitives.js
Normal file
67
packages/graphics/primitives.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
|
||||
|
||||
import {Color} from './color';
|
||||
import {Renderable} from './renderable';
|
||||
|
||||
export class Primitives extends Renderable {
|
||||
|
||||
static fillStyle(color) {
|
||||
return {color};
|
||||
}
|
||||
|
||||
static lineStyle(color, thickness = 1) {
|
||||
return {color, thickness};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.internal = new PIXI.Graphics();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.internal.clear();
|
||||
}
|
||||
|
||||
drawCircle(position, radius, lineStyle, fillStyle) {
|
||||
this._wrapStyle('drawCircle', '3rd', lineStyle, fillStyle, () => {
|
||||
this.internal.drawCircle(position[0], position[1], radius);
|
||||
});
|
||||
}
|
||||
|
||||
drawLine(p1, p2, lineStyle, fillStyle) {
|
||||
this._wrapStyle('drawLine', '3rd', lineStyle, fillStyle, () => {
|
||||
this.internal.moveTo(p1[0], p1[1]);
|
||||
this.internal.lineTo(p2[0], p2[1]);
|
||||
});
|
||||
}
|
||||
|
||||
drawRectangle(rectangle, lineStyle, fillStyle) {
|
||||
this._wrapStyle('drawLine', '2nd', lineStyle, fillStyle, () => {
|
||||
this.internal.drawRect(
|
||||
rectangle[0],
|
||||
rectangle[1],
|
||||
rectangle[2],
|
||||
rectangle[3]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_wrapStyle(method, where, lineStyle, fillStyle, fn) {
|
||||
if (!lineStyle) {
|
||||
throw new TypeError(
|
||||
`Primitives::${method} expects lineStyle as ${where} parameter`
|
||||
);
|
||||
}
|
||||
if (fillStyle) {
|
||||
const {color} = fillStyle;
|
||||
this.internal.beginFill(color.toInteger(), color.alpha)
|
||||
}
|
||||
const {color, thickness} = lineStyle;
|
||||
this.internal.lineStyle(thickness, color.toInteger(), color.alpha)
|
||||
fn();
|
||||
if (fillStyle) {
|
||||
this.internal.endFill();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
57
packages/graphics/renderable.js
Normal file
57
packages/graphics/renderable.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
export class Renderable {
|
||||
|
||||
get alpha() {
|
||||
return this.internal.alpha;
|
||||
}
|
||||
|
||||
set alpha(alpha) {
|
||||
this.internal.alpha = alpha;
|
||||
}
|
||||
|
||||
get isValid() {
|
||||
return !!this.internal;
|
||||
}
|
||||
|
||||
get position() {
|
||||
return [this.internal.x, this.internal.y];
|
||||
}
|
||||
|
||||
set position(position) {
|
||||
this.internal.x = position[0];
|
||||
this.internal.y = position[1];
|
||||
}
|
||||
|
||||
get rotation() {
|
||||
return this.internal.rotation;
|
||||
}
|
||||
|
||||
set rotation(rotation) {
|
||||
this.internal.rotation = rotation;
|
||||
}
|
||||
|
||||
get visible() {
|
||||
return this.internal.visible;
|
||||
}
|
||||
|
||||
set visible(isVisible) {
|
||||
this.internal.visible = isVisible;
|
||||
}
|
||||
|
||||
get x() {
|
||||
return this.internal.x;
|
||||
}
|
||||
|
||||
set x(x) {
|
||||
this.internal.x = x;
|
||||
}
|
||||
|
||||
get y() {
|
||||
return this.internal.y;
|
||||
}
|
||||
|
||||
set y(y) {
|
||||
this.internal.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
|
45
packages/graphics/renderer.js
Normal file
45
packages/graphics/renderer.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
|
||||
|
||||
export class Renderer {
|
||||
|
||||
constructor(size, type = 'auto') {
|
||||
switch (type) {
|
||||
case 'auto':
|
||||
this.renderer = PIXI.autoDetectRenderer(size[0], size[1]);
|
||||
break;
|
||||
case 'canvas':
|
||||
this.renderer = new PIXI.CanvasRenderer(size[0], size[1]);
|
||||
break;
|
||||
case 'auto':
|
||||
this.renderer = new PIXI.Renderer(size[0], size[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.renderer.destroy();
|
||||
}
|
||||
|
||||
get element() {
|
||||
return this.renderer.view;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.element.height;
|
||||
}
|
||||
|
||||
render(item) {
|
||||
this.renderer.render(item.internal);
|
||||
}
|
||||
|
||||
get size() {
|
||||
return [this.width, this.height];
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.element.width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
26
packages/graphics/sprite.js
Normal file
26
packages/graphics/sprite.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
const PIXI = 'undefined' !== typeof window ? require('pixi.js') : undefined;
|
||||
|
||||
import {Renderable} from './renderable';
|
||||
|
||||
export class Sprite extends Renderable {
|
||||
|
||||
constructor(image) {
|
||||
super();
|
||||
this._image = image;
|
||||
this.internal = new PIXI.Sprite(image.texture);
|
||||
}
|
||||
|
||||
get image() {
|
||||
return this._image;
|
||||
}
|
||||
|
||||
setSourceRectangle(rectangle) {
|
||||
this._image.texture.frame = {
|
||||
x: rectangle[0],
|
||||
y: rectangle[1],
|
||||
width: rectangle[2],
|
||||
height: rectangle[3],
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user