Commit bd7b8e7c authored by rockyl's avatar rockyl

Merge branch 'mvvm'

# Conflicts:
#	manifest.json
parents d82d3f53 07abf962
This diff is collapsed.
This diff is collapsed.
module.exports = {
region: 'oss-cn-hangzhou',
id: 'LTAIqO2wblIxQvwc',
secret: '4brsaSRbRpjxw3oDIxJi6bNMcndIR6',
id: 'LTAI4Fw25WcfcGv7FvcHoiHK',
secret: 'NZk1NtT9J5HFaAolNbtQdzTzLLvLYm',
bucket: 'duiba',
output: '/editor/zeroing/libs'
};
{
"name": "aaaa",
"version": "1.0.0",
"name": "zeroing-engine",
"version": "0.1.0",
"description": "",
"main": "index.js",
"types": "index.d.ts",
......@@ -30,7 +30,8 @@
"build:debug": "rm -rf dist&&yarn build && yarn preprocess && ali-oss-publish -c oss.config.js -e dist",
"ts": "dts-bundle --name engine --main types/src/index.d.ts --out ../../dist/index.d.ts",
"test": "echo \"Error: no test specified\" && exit 1",
"mergeDts": "node scripts/mergeDts.js"
"mergeDts": "node scripts/mergeDts.js",
"token": "uglifyjs -m -c -o px-token.min.js px-token.js"
},
"author": "",
"license": "ISC"
......
function getPxToken(callback) {
if (window['ohjaiohdf']) {
var xhr = new XMLHttpRequest();
xhr.open('get', 'getToken', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.response);
if (response.success) {
window.eval(response.data);
callback(null, window['ohjaiohdf']());
} else {
switch(response.code){
case '100001':
callback('need login');
break;
case '100024':
callback('state invalid');
break;
default:
callback(response.code);
break;
}
}
}
};
xhr.onerror = function (e) {
failedCallback();
};
xhr.onloadend = function () {
if (xhr.status === 404) {
failedCallback();
}
};
xhr.send();
} else {
callback('need login');
}
function failedCallback() {
callback('net error');
}
}
function getPxToken(n){if(window.ohjaiohdf){var o=new XMLHttpRequest;o.open("get","getToken",!0),o.onreadystatechange=function(){if(4===o.readyState&&200===o.status){var e=JSON.parse(o.response);if(e.success)window.eval(e.data),n(null,window.ohjaiohdf());else switch(e.code){case"100001":n("need login");break;case"100024":n("state invalid");break;default:n(e.code)}}},o.onerror=function(e){t()},o.onloadend=function(){404===o.status&&t()},o.send()}else n("need login");function t(){n("net error")}}
\ No newline at end of file
......@@ -423,11 +423,11 @@ export default class Container extends DisplayObject {
}
}
if(this._transform === this.transform && isUI(this) && this._lastLocalID !== this.transform.localID){
/*if(this._transform === this.transform && isUI(this) && this._lastLocalID !== this.transform.localID){
this._lastLocalID = this.transform.localID;
//console.log(this.name, this.instanceId , 'dirty!');
this.stage.layoutInvalid = true;
}
}*/
}
/**
......@@ -467,14 +467,7 @@ export default class Container extends DisplayObject {
}
}
let widthSetted = !!this._width && this._width !== 0;
let heightSetted = !!this._height && this._height !== 0;
if (widthSetted) {
this._bounds.width = this._width;
}
if (heightSetted) {
this._bounds.height = this._height;
}
}
/**
......@@ -482,6 +475,28 @@ export default class Container extends DisplayObject {
*/
protected _calculateBounds() {
//子类自己重写
//let wp = this.worldMatrix.transformPoint(this.x, this.y);
let widthSetted = !!this._width && this._width !== 0;
let heightSetted = !!this._height && this._height !== 0;
/*if (widthSetted) {
this._bounds.x = this.x;
this._bounds.width = this._width;
}
if (heightSetted) {
this._bounds.y = this.y;
this._bounds.height = this._height;
}*/
if(widthSetted || heightSetted){
const rect = this._localBoundsSelf;
var matrix = this.transform.worldMatrix;
matrix.transformPoint(rect.x, rect.y, DisplayObject._p1);
matrix.transformPoint(rect.x + rect.width, rect.y, DisplayObject._p2);
matrix.transformPoint(rect.x + rect.width, rect.y + rect.height, DisplayObject._p3);
matrix.transformPoint(rect.x, rect.y + rect.height, DisplayObject._p4);
Rectangle.createFromPoints(this._bounds, DisplayObject._p1, DisplayObject._p2, DisplayObject._p3, DisplayObject._p4);
}
}
/**
......@@ -492,7 +507,9 @@ export default class Container extends DisplayObject {
//如果不可见
if (!this.visible) return null
//如果禁止子级的鼠标事件
if (isMouseEvent && !this.mouseChildren) return this.hitTestSelf(globalPoint);
if (isMouseEvent && !this.mouseChildren){
return this.hitTestSelf(globalPoint);
}
var children = this.children;
var length = children.length;
let child, hitDisplayObject;
......@@ -509,7 +526,7 @@ export default class Container extends DisplayObject {
if (hitDisplayObject) return hitDisplayObject;
}
return this.hitTestSelf(globalPoint);
return this.displayObjectHitTestPoint(globalPoint, isMouseEvent);
}
hitTestSelf(globalPoint) {
......@@ -520,12 +537,14 @@ export default class Container extends DisplayObject {
}
hitTestSelfBounds(globalPoint) {
if (this.width && this.height) {
let lp = this.globalToLocal(globalPoint, DisplayObject._bp);
if (lp.x > 0 &&
lp.x < this.width &&
lp.y > 0 &&
lp.y < this.height
if (this._width && this._height) {
//let {x: tx, y: ty} = this.getBounds();
let {tx, ty} = this.worldMatrix;
const {x, y} = globalPoint;
if (x > tx &&
x < tx + this.width &&
y > ty &&
y < ty + this.height
) return this;
}
return null
......@@ -699,7 +718,8 @@ export default class Container extends DisplayObject {
if (this._width !== value) {
//子类有用,有_width,才需设置scaleX
this._width = value;
if(this.stage) this.stage.layoutInvalid = true;
this._localBoundsSelf.width = value;
//if (this.stage) this.stage.layoutInvalid = true;
this.dispatchEvent(Event.RESIZE);
}
}
......@@ -722,7 +742,8 @@ export default class Container extends DisplayObject {
// }
if (this._height !== value) {
this._height = value;
if(this.stage) this.stage.layoutInvalid = true;
this._localBoundsSelf.height = value;
//if (this.stage) this.stage.layoutInvalid = true;
this.dispatchEvent(Event.RESIZE);
}
}
......@@ -730,8 +751,10 @@ export default class Container extends DisplayObject {
clone(withEvents = false, withScripts = false) {
let target = this.constructor.apply(Object.create(this.constructor.prototype));
const {name, properties, events, scripts} = this['__originConfig'];
const originConfig = this['__originConfig'];
const {name, properties, events, scripts} = originConfig;
target.name = name;
target['__originConfig'] = originConfig;
injectProperties(target, properties);
if (withScripts) {
......@@ -755,6 +778,21 @@ export default class Container extends DisplayObject {
return target;
}
get $store() {
let p = this;
do {
if (p['$isViewRoot']) {
break;
}
p = p.parent;
}
while (p.parent);
if (p) {
return p['$_store'];
}
}
//全局遍历
/**
* @method _getElementsByName
......
......@@ -280,6 +280,10 @@ export class DisplayObject extends EventDispatcher {
this.parent = parentRef;
this.transform = transformRef;
if (this.parent && this.stage) {
this.updateTransform();
}
return bounds;
}
......@@ -609,14 +613,17 @@ export class DisplayObject extends EventDispatcher {
}
set mask(value) {
if (value === this) {
return;
}
if (this.$mask) {
//原先有的遮罩,重置属性
this.$mask.renderable = true;
this.$mask.isUsedToMask = false;
if (this.$mask.parent) {
/*if (this.$mask.parent) {
this.$mask.parent.removeChild(this.$mask)
//是否销毁
}
}*/
}
this.$mask = value;
......
......@@ -158,6 +158,7 @@ export default class Sprite extends Container {
this._localBoundsSelf.width = width;
this._localBoundsSelf.height = height;
this.dispatchEvent(Event.COMPLETE);
this.dispatchEvent(Event.RESIZE);
}
......
......@@ -42,7 +42,9 @@ export const requestAnimationFrame = (function () {
};
}
return requestAnimationFrame
}())
}());
const skipTagNames = ['INPUT'];
export class Stage extends Container {
......@@ -115,11 +117,6 @@ export class Stage extends Container {
*/
private static _stageList: any = {};
/**
* 布局失效
*/
layoutInvalid: boolean = false;
/**
* 是否暂停
* @property pause
......@@ -438,7 +435,7 @@ export class Stage extends Container {
s.dispatchEvent(Event.ON_INIT_STAGE);
// }
}, 100);
let rc = s.rootDiv;//canvas
let rc = s.rootDiv; //canvas
let mouseEvent = s.onMouseEvent.bind(s);
//鼠标事件
if (osType != "pc") {
......@@ -616,6 +613,9 @@ export class Stage extends Container {
*/
private onMouseEvent(e: any): void {
let s: Stage = this;
if (skipTagNames.indexOf(e.target.tagName) >= 0) {
return;
}
//检查mouse或touch事件是否有,如果有的话,就触发事件函数
if (EventDispatcher._totalMEC > 0) {
let points: any;
......@@ -1017,14 +1017,6 @@ export class Stage extends Container {
}
}
afterUpdateTransform() {
/*this.calculateBounds();
if (this.layoutInvalid) {
this.dispatchEvent(Event.LAYOUT_INVALID);
this.layoutInvalid = false;
}*/
}
public destroy(): void {
let s = this;
Stage.removeUpdateObj(s);
......
This diff is collapsed.
import { calculatePlaneIndices } from './Plane';
import { Texture } from '../texture';
import CanvasRenderer from '../renderers/CanvasRenderer';
import { Mesh } from './Mesh';
//提前计算好的索引
const indicesNN = calculatePlaneIndices(4, 4)
/**
* 九宫格
*```js
* let Plane9 = new NineSlicePlane(Texture.fromUrl('BoxWithRoundedCorners.png'), 15, 15, 15, 15);
* ```0,1,3,5,7,8,16,24,都是0
*
* 0...1...2...3
* . . . .
* 4...5...6...7
* . . . .
* 8...9...10..11
* . . . .
* 12..13..14..15
* <pre>
* A B
* +---+----------------------+---+
* C | 1 | 2 | 3 |
* +---+----------------------+---+
* | | | |
* | 4 | 5 | 6 |
* | | | |
* +---+----------------------+---+
* D | 7 | 8 | 9 |
* +---+----------------------+---+
* 当修改宽高width height时,不再改变scale属性
* 1 3 7 9 永远不变
* 2 8 只会水平横向拉伸
* 4 6 只会垂直纵向拉伸
* 5 都会拉伸
* </pre>
*
*
*/
export class NineSlicePlane extends Mesh {
/**
* 宽高get set都重写,不再修改缩放,修改uv和顶点
*/
get width(): number {
return this._width;
}
set width(value: number) {
this._width = value;
this._needRefresh = true;
}
get height(): number {
return this._height;
}
set height(value: number) {
this._height = value;
this._needRefresh = true;
}
/**
* 原始宽度
*/
private _origWidth: number;
/**
* 原始高度
*/
private _origHeight: number;
/**
* 左边宽度
*/
private _leftWidth: number;
get leftWidth(): number {
return this._leftWidth;
}
set leftWidth(value: number) {
this._leftWidth = value;
this._needRefresh = true;
}
/**
* 右边宽度
*/
private _rightWidth: number;
get rightWidth(): number {
return this._rightWidth;
}
set rightWidth(value: number) {
this._rightWidth = value;
this._needRefresh = true;
}
/**
* 上边高度
*/
private _topHeight: number;
get topHeight(): number {
return this._topHeight;
}
set topHeight(value: number) {
this._topHeight = value;
this._needRefresh = true;
}
/**
* 下边高度
*/
private _bottomHeight: number;
get bottomHeight(): number {
return this._bottomHeight;
}
set bottomHeight(value: number) {
this._bottomHeight = value;
this._needRefresh = true;
}
/**
* @param {Texture} texture
* @param {number} [leftWidth=10]
* @param {number} [topHeight=10]
* @param {number} [rightWidth=10]
* @param {number} [bottomHeight=10]
*/
constructor(texture: Texture, leftWidth: number = 10, topHeight: number = 10, rightWidth: number = 10, bottomHeight: number = 10) {
super(texture);
//考虑对于未加载好的图片怎么处理吧,肯定需要加在onTextureUpdate的
this._origWidth = texture.orig.width;
this._origHeight = texture.orig.height;
this._width = this._origWidth;
this._height = this._origHeight;
this._leftWidth = leftWidth;
this._rightWidth = rightWidth;
this._topHeight = topHeight;
this._bottomHeight = bottomHeight;
//计算索引,完全不用变,所以提前计算
this._indices = indicesNN;
//顶点数量长度可以确定先
this._vertices = new Float32Array(4 * 4 * 2);
//uv长度也可以确定先
this._uvs = new Float32Array(4 * 4 * 2);
this.refresh(true);
}
/**
* 额外增加修改原始宽高
*/
protected _onTextureUpdate() {
super._onTextureUpdate();
this._origWidth = this.texture.orig.width;
this._origHeight = this.texture.orig.height;
}
/**
* 计算横向顶点
*/
private updateHorizontalVertices() {
const vertices = this._vertices;
const h = this._topHeight + this._bottomHeight;
const scale = this._height > h ? 1.0 : this._height / h;
vertices[9] = vertices[11] = vertices[13] = vertices[15] = this._topHeight * scale;
vertices[17] = vertices[19] = vertices[21] = vertices[23] = this._height - (this._bottomHeight * scale);
vertices[25] = vertices[27] = vertices[29] = vertices[31] = this._height;
}
/**
* 计算纵向顶点
*/
private updateVerticalVertices() {
const vertices = this._vertices;
const w = this._leftWidth + this._rightWidth;
const scale = this._width > w ? 1.0 : this._width / w;
vertices[2] = vertices[10] = vertices[18] = vertices[26] = this._leftWidth * scale;
vertices[4] = vertices[12] = vertices[20] = vertices[28] = this._width - (this._rightWidth * scale);
vertices[6] = vertices[14] = vertices[22] = vertices[30] = this._width;
}
/**
*
* 考虑是否用缓存,不然每次相当于9次绘制,到时应该是集成到一个插件里的
* @private
* @param {CanvasRenderer} renderer
*/
_renderCanvas(renderer: CanvasRenderer) {
const context = renderer.context;
context.globalAlpha = this._worldAlpha;
renderer.setBlendMode(this.blendMode);
const transform = this.worldMatrix;
context.setTransform(
transform.a,
transform.b,
transform.c,
transform.d,
transform.tx,
transform.ty
);
const base = this.texture.baseTexture;
const textureSource = base.source;
const w = base.width;
const h = base.height;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
this.drawSegment(context, textureSource, w, h, 4, 5, 14, 15);
this.drawSegment(context, textureSource, w, h, 8, 9, 18, 19);
this.drawSegment(context, textureSource, w, h, 10, 11, 20, 21);
this.drawSegment(context, textureSource, w, h, 12, 13, 22, 23);
this.drawSegment(context, textureSource, w, h, 16, 17, 26, 27);
this.drawSegment(context, textureSource, w, h, 18, 19, 28, 29);
this.drawSegment(context, textureSource, w, h, 20, 21, 30, 31);
}
/**
* 分部画
* 每部分保证至少有1像素
* @private
* @param {CanvasRenderingContext2D} context
* @param {CanvasImageSource} textureSource - 图片资源
* @param {number} w - 贴图宽
* @param {number} h - 贴图高
* @param {number} x1 - x index 1
* @param {number} y1 - y index 1
* @param {number} x2 - x index 2
* @param {number} y2 - y index 2
*/
private drawSegment(
context: CanvasRenderingContext2D,
textureSource: HTMLImageElement | HTMLCanvasElement,
w: number,
h: number,
x1: number,
y1: number,
x2: number,
y2: number
) {
const uvs = this._uvs;
const vertices = this._vertices;
let sw = (uvs[x2] - uvs[x1]) * w;
let sh = (uvs[y2] - uvs[y1]) * h;
let dw = vertices[x2] - vertices[x1];
let dh = vertices[y2] - vertices[y1];
//绘制源保证至少有一像素
if (sw < 1) sw = 1;
if (sh < 1) sh = 1;
//绘制体保证至少一像素
if (dw < 1) dw = 1;
if (dh < 1) dh = 1;
context.drawImage(textureSource, uvs[x1] * w, uvs[y1] * h, sw, sh, vertices[x1], vertices[y1], dw, dh);
}
/**
* 计算所有坐标
*/
_refresh() {
const uvs = this._uvs;
const texture = this.texture;
this._origWidth = texture.orig.width;
this._origHeight = texture.orig.height;
const _uvw = 1.0 / this._origWidth;
const _uvh = 1.0 / this._origHeight;
uvs[0] = uvs[8] = uvs[16] = uvs[24] = 0;
uvs[1] = uvs[3] = uvs[5] = uvs[7] = 0;
uvs[6] = uvs[14] = uvs[22] = uvs[30] = 1;
uvs[25] = uvs[27] = uvs[29] = uvs[31] = 1;
uvs[2] = uvs[10] = uvs[18] = uvs[26] = _uvw * this._leftWidth;
uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - (_uvw * this._rightWidth);
uvs[9] = uvs[11] = uvs[13] = uvs[15] = _uvh * this._topHeight;
uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - (_uvh * this._bottomHeight);
this.updateHorizontalVertices();
this.updateVerticalVertices();
this._vertexDirty++;
this.multiplyUvs();
}
}
import { Mesh } from './Mesh';
import { Texture } from '../texture';
/**
* 根据分段数的平面
* verticesX和verticesY都是xy轴上的顶点数,比分段数多1
*
*/
export class Plane extends Mesh {
/**
* x轴顶点数目
*/
private _verticesX: number;
get verticesX(): number {
return this._verticesX
}
set verticesX(value: number) {
if (this._verticesX !== value) {
this._verticesX = value
this._needRefresh = true;
}
}
/**
* y轴顶点数目
*/
private _verticesY: number;
get verticesY(): number {
return this._verticesY
}
set verticesY(value: number) {
if (this._verticesY !== value) {
this._verticesY = value
this._needRefresh = true;
}
}
/**
* @param {Texture} texture
* @param {int} [verticesX=10]
* @param {int} [verticesY=10]
*/
constructor(texture: Texture, verticesX: number = 10, verticesY: number = 10) {
super(texture);
this._verticesX = verticesX;
this._verticesY = verticesY;
this.refresh();
}
/**
* 计算所有坐标
*/
_refresh() {
const texture = this.texture;
const total = this.verticesX * this.verticesY;
const verts = [];
const uvs = [];
const segmentsX = this.verticesX - 1;
const segmentsY = this.verticesY - 1;
const sizeX = texture.width / segmentsX;
const sizeY = texture.height / segmentsY;
for (let i = 0; i < total; i++) {
const x = (i % this.verticesX);
const y = ((i / this.verticesX) | 0);
verts.push(x * sizeX, y * sizeY);
uvs.push(x / segmentsX, y / segmentsY);
}
this._vertices = new Float32Array(verts);
this._uvs = new Float32Array(uvs);
this._indices = calculatePlaneIndices(this.verticesX, this.verticesY);
//标记dirty
this._vertexDirty++;
this.multiplyUvs();
}
}
/**
* 计算平面的索引
* @param verticesX x轴上的顶点数量,最小2
* @param verticesY y轴上的顶点数量,最小2
*/
export function calculatePlaneIndices(verticesX: number, verticesY: number): Uint16Array {
const segmentsX = verticesX - 1;
const segmentsY = verticesY - 1;
const totalSub = segmentsX * segmentsY;
const indices = [];
for (let i = 0; i < totalSub; i++) {
const xpos = i % segmentsX;
const ypos = (i / segmentsX) | 0;
const value = (ypos * verticesX) + xpos;
const value2 = (ypos * verticesX) + xpos + 1;
const value3 = ((ypos + 1) * verticesX) + xpos;
const value4 = ((ypos + 1) * verticesX) + xpos + 1;
indices.push(value, value2, value3);
indices.push(value2, value4, value3);
}
return new Uint16Array(indices);
}
import { Mesh } from './Mesh';
import { Texture } from '../texture';
import { Point } from '../math';
/**
* 为了能加入批处理,不用TRIANGLE_STRIP方式渲染(有需要看v4版本的pixi),还是用TRIANGLE
*```js
* for (let i = 0; i < 20; i++) {
* points.push(new Point(i * 50, 0));
* };
* let rope = new Rope(Texture.fromUrl("snake.png"), points);
* ```
*
*
*/
export class Rope extends Mesh {
/**
* 一组点
*/
points: Point[];
/**
* 是否自动更新顶点,为true,自动更新顶点,否则在points里顶点修改后,自行refreshVertices
*/
autoUpdateVertices: boolean;
/**
* 以横向的为基准,纹理高度
*/
private textureHeight: number;
/**
* @param {Texture} texture
* @param {Point[]} points
*/
constructor(texture: Texture, points: Point[]) {
super(texture);
this.points = points;
this._vertices = new Float32Array(points.length * 4);
this._uvs = new Float32Array(points.length * 4);
this._indices = new Uint16Array((points.length - 1) * 6);
this.textureHeight = texture.height;
this.refresh(true);
this.refreshVertices();
}
/**
* 计算索引和uv,和顶点计算的要分开
*/
_refresh() {
const points = this.points;
//没点,或贴图uv为空
if (points.length < 1 || !this.texture._uvs) return;
//如果顶点数量有变
if (this._vertices.length / 4 !== points.length) {
this._vertices = new Float32Array(points.length * 4);
this._uvs = new Float32Array(points.length * 4);
this._indices = new Uint16Array((points.length - 1) * 6);
}
const uvs = this._uvs;
const indices = this._indices;
uvs[0] = 0;
uvs[1] = 0;
uvs[2] = 0;
uvs[3] = 1;
// indices[0] = 0;
// indices[1] = 1;
const total = points.length;
for (let i = 1; i < total; i++) {
// time to do some smart drawing!
let index = i * 4;
const amount = i / (total - 1);
uvs[index] = amount;
uvs[index + 1] = 0;
uvs[index + 2] = amount;
uvs[index + 3] = 1;
}
let indexCount = 0;
for (let i = 0; i < total - 1; i++) {
const index = i * 2;
indices[indexCount++] = index;
indices[indexCount++] = index + 1;
indices[indexCount++] = index + 2;
indices[indexCount++] = index + 2;
indices[indexCount++] = index + 1;
indices[indexCount++] = index + 3;
}
this.multiplyUvs();
// this.refreshVertices();
}
/**
* 根据points刷新顶点
*/
refreshVertices() {
const points = this.points;
//
if (points.length < 1) return;
//如果points数量修改过,去执行_refresh
if (this._vertices.length / 4 !== points.length) {
this._refresh();//里面肯定会把_vertices的长度矫正
this.refreshVertices();
return;
}
let lastPoint = points[0];
let nextPoint;
let perpX = 0;
let perpY = 0;
// this.count -= 0.2;
const vertices = this._vertices;
const total = points.length;
for (let i = 0; i < total; i++) {
const point = points[i];
const index = i * 4;
if (i < points.length - 1) {
nextPoint = points[i + 1];
}
else {
nextPoint = point;
}
perpY = -(nextPoint.x - lastPoint.x);
perpX = nextPoint.y - lastPoint.y;
let ratio = (1 - (i / (total - 1))) * 10;
if (ratio > 1) {
ratio = 1;
}
const perpLength = Math.sqrt((perpX * perpX) + (perpY * perpY));
const num = this.textureHeight / 2; // (20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio;
perpX /= perpLength;
perpY /= perpLength;
perpX *= num;
perpY *= num;
vertices[index] = point.x + perpX;
vertices[index + 1] = point.y + perpY;
vertices[index + 2] = point.x - perpX;
vertices[index + 3] = point.y - perpY;
lastPoint = point;
}
//标记修改
this._vertexDirty++;
}
update() {
super.update();
//自动更新顶点,或者纹理高度有修改
if (this.autoUpdateVertices || this.textureHeight !== this.texture.height) {
this.textureHeight = this.texture.height
this.refreshVertices();
}
}
}
export * from "./Mesh"
export * from "./NineSlicePlane"
export * from "./Plane"
export * from "./Rope"
\ No newline at end of file
......@@ -2,7 +2,7 @@
* Created by rockyl on 2019-11-22.
*/
import {injectProperties, obj2query} from "../zeroing/utils";
import {injectProperties, obj2query} from "../zeroing/utils/index";
import {queryParams} from "../zeroing/web";
/**
......
......@@ -134,8 +134,6 @@ export default class CanvasRenderer extends SystemRenderer {
displayObject.updateTransform();
displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//初始化上下文状态
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
......
......@@ -179,8 +179,6 @@ export class WebglRenderer extends SystemRenderer {
displayObject.updateTransform();
displayObject.parent = cacheParent;
displayObject.stage && displayObject.stage.afterUpdateTransform();
//绑定渲染对象,没有则是默认root
this.bindRenderTexture(renderTexture, transform);
......
This diff is collapsed.
......@@ -271,7 +271,7 @@ export class ScrollViewBase extends Container {
}
protected calMaxDistance(){
return this.viewPort[this.paramSize];
return this.viewPort[this.paramSize] + this.viewPort.getLocalBounds()[this.paramXY]
}
get direction(): SCROLL_DIRECTION {
......
......@@ -4,7 +4,7 @@
* 过程
*/
import {VM} from "./VM";
import {getDataByPath, linkedFlag, linkScheme, nodeScheme, objClone} from "../utils";
import {getDataByPath, linkScheme, nodeScheme, objClone} from "../utils/index";
import {dataCenter} from "../game-warpper/data-center";
import {env} from "../game-warpper/enviroment";
import {getLogSwitch, Logs} from "../log-switch";
......@@ -241,7 +241,7 @@ export class Process {
props[key] = nameValue !== undefined ? nameValue : dataCenter.getDataByPath(name);
break;
case 'env':
props[key] = env[name];
props[key] = getDataByPath(env, name);
break;
case 'map':
this.updateProps(props[key] = {}, args, name, name);
......
......@@ -7,14 +7,16 @@ import {StackContainer} from "./StackContainer";
import {loadAssets} from "./assets-manager";
import {instantiate} from "./view-interpreter";
import {dataCenter, DataCenter} from "./data-center";
import {setProcessMetaLibs} from "../behavior-runtime";
import {Tween} from "../../2d/tween";
import {Rect} from "./nodes";
import {setProcessMetaLibs} from "../behavior-runtime/index";
import {Tween} from "../../2d/tween/index";
import {Rect} from "./nodes/index";
import {injectEnv} from "./enviroment";
import {Toast} from "./Toast";
import {arrayFind} from "../utils";
import {registerCustomModules, registerScripts} from "..";
import {arrayFind} from "../utils/index";
import {Node} from "./nodes/Node";
import {bind, createStore} from "./mvvm/index";
import {registerCustomModules} from "./custom-module";
import {dealPageRemainTime, dealPxEnv} from "../px-logics";
/**
* 游戏舞台
......@@ -62,6 +64,7 @@ export class GameStage extends Node {
this._popupContainer.name = 'popup-container';
this._popupContainer.addEventListener('change', this.onPopupContainerChange, this);
}
/**
......@@ -126,6 +129,9 @@ export class GameStage extends Node {
this.start();
dealPxEnv();
dealPageRemainTime();
onStart && onStart();
function p() {
......@@ -180,6 +186,23 @@ export class GameStage extends Node {
let viewConfig = this.getViewConfigByName(name);
if (viewConfig) {
view = instantiate(viewConfig);
let store = {};
if (viewConfig.store) {
const {exp, computed} = viewConfig.store;
store = createStore(exp, computed);
}
view['$isViewRoot'] = true;
view['$_store'] = store;
/*let label = view.children[0];
label['z-for'] = 'item in list';*/
console.time('bind');
bind(store, view);
console.timeEnd('bind');
if (cache) {
this._viewCache[name] = view;
}
......
......@@ -56,7 +56,7 @@ export class StackContainer extends Node {
*/
pop(dispatch = true) {
let len = this.children.length;
if (len == 0) {
if (len <= 0) {
return false;
}
this.removeChildAt(len - 1);
......
......@@ -84,7 +84,7 @@ export class DataCenter extends EventDispatcher {
let name = args[0];
let dataMapping = this.getDataMapping(name);
try {
let data: any = this.getDataByPath(dataMapping.path, undefined, true);
let data: any = this.getDataByPath(dataMapping.path, undefined, false);
if (args[1] !== undefined) {
data = data[args[1]];
}
......
......@@ -2,7 +2,7 @@
* Created by rockyl on 2019-11-21.
*/
export let env = {};
export let env:any = {};
export function injectEnv(data){
if(data){
......
......@@ -9,3 +9,4 @@ export * from './nodes'
export * from './sound'
export * from './assets-manager'
export * from './texture-sheet'
export * from './data-center'
/**
* Created by Raykid on 2016/12/16.
*/
import {IAres, Compiler, AresOptions, IWatcher, WatcherCallback, AresCommandData} from "./Interfaces";
import {Mutator} from "./Mutator";
import {Watcher} from "./Watcher";
import {CommandContext, Command, commands} from "./Commands"
export const defaultCmdRegExp:RegExp = /^(data\-)?a[\-_](\w+)([:\$](.+))?$/;
/**
* 将数据模型和视图进行绑定
* @param data
* @param compiler 视图解析器,不同类型的视图需要使用不同的解析器解析后方可使用
* @param options 一些额外参数
* @returns {IAres} 绑定实体对象
*/
export function bind(data:any, compiler:Compiler, options?:AresOptions):IAres
{
return new Ares(data, compiler, options);
}
export class Ares implements IAres
{
private _data:any;
private _compiler:Compiler;
private _options:any;
/** 获取ViewModel */
public get data():any
{
return this._data;
}
/** 获取编译器 */
public get compiler():Compiler
{
return this._compiler;
}
public constructor(data:any, compiler:Compiler, options?:AresOptions)
{
// 记录变异对象
this._data = Mutator.mutate(data);
this._compiler = compiler;
this._options = options;
// 初始化Compiler
this._compiler.init(this);
// 调用回调
if(this._options && this._options.inited)
{
this._options.inited.call(this._data, this);
}
}
public createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher
{
return new Watcher(this, target, exp, scope, callback);
}
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @param cmdRegExp 可选,如果不传则使用默认的命令正则表达式解析命令
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
public parseCommand(key:string, value:string, cmdRegExp?:RegExp):AresCommandData
{
var result:RegExpExecArray = (cmdRegExp || defaultCmdRegExp).exec(key);
if(!result) return null;
// 取到key
var key:string = result[0];
// 取到命令名
var cmdName:string = result[2];
// 取到命令字符串
var exp:string = value;
// 取到子命令名
var subCmd:string = result[4] || "";
// 返回结构体
return {
cmdName: cmdName,
subCmd: subCmd,
propName: key,
exp: exp
};
}
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public testCommand(data:AresCommandData):boolean
{
// 非空判断
if(!data) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
return (cmd != null);
}
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public execCommand(data:AresCommandData, target:any, scope:any):boolean
{
// 非空判断
if(!data || !scope) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
// 没找到命令就返回false
if(!cmd) return false;
// 找到命令了,执行之
cmd({
target: target,
scope: scope,
entity: this,
data: data
});
return true;
}
}
\ No newline at end of file
......@@ -2,15 +2,15 @@
* Created by Raykid on 2017/7/19.
*/
import {IAres, AresCommandData} from "./Interfaces"
import {IZri, ZriCommandData} from "./Interfaces"
import {runExp} from "./Utils"
export interface CommandContext
{
target:any;
scope:any;
entity:IAres;
data:AresCommandData;
entity:IZri;
data:ZriCommandData;
}
export interface Command
......
......@@ -4,32 +4,27 @@
import {Watcher} from "./Watcher";
export class Dep
{
private _map:{[uid:number]:Watcher} = {};
export class Dep {
private _map: { [uid: number]: Watcher } = {};
/**
* 添加数据变更订阅者
* @param watcher 数据变更订阅者
*/
public watch(watcher:Watcher):void
{
if(!this._map[watcher.uid])
{
this._map[watcher.uid] = watcher;
}
}
/**
* 添加数据变更订阅者
* @param watcher 数据变更订阅者
*/
public watch(watcher: Watcher): void {
if (!this._map[watcher.uid]) {
this._map[watcher.uid] = watcher;
}
}
/**
* 数据变更,通知所有订阅者
* @param extra 可能的额外数据
*/
public notify(extra?:any):void
{
for(var uid in this._map)
{
var watcher:Watcher = this._map[uid];
watcher.update(extra);
}
}
/**
* 数据变更,通知所有订阅者
* @param extra 可能的额外数据
*/
public notify(extra?: any): void {
for (var uid in this._map) {
var watcher: Watcher = this._map[uid];
watcher.update(extra);
}
}
}
\ No newline at end of file
......@@ -7,9 +7,9 @@ export interface Compiler
root:any;
/**
* 初始化编译器
* @param entity Ares实例
* @param entity Zri实例
*/
init(entity:IAres):void;
init(entity:IZri):void;
/**
* 编译方法
* @param target 要编译的显示节点
......@@ -18,7 +18,7 @@ export interface Compiler
compile(target:any, scope:any):void;
}
export interface IAres
export interface IZri
{
/** 获取ViewModel */
data:any;
......@@ -35,17 +35,17 @@ export interface IAres
createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher;
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以a-或a_开头,以:或$分隔主命令和子命令
* @param key 属性名,合法的属性名应以z-或z_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
parseCommand(key:string, value:string):AresCommandData;
parseCommand(key:string, value:string):ZriCommandData;
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
testCommand(data:AresCommandData):boolean;
testCommand(data:ZriCommandData):boolean;
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
......@@ -53,12 +53,12 @@ export interface IAres
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
execCommand(data:AresCommandData, target:any, scope:any):boolean
execCommand(data:ZriCommandData, target:any, scope:any):boolean
}
export interface AresOptions
export interface ZriOptions
{
inited?:(entity?:IAres)=>void;
inited?:(entity?:IZri)=>void;
}
export interface IWatcher
......@@ -82,7 +82,7 @@ export interface WatcherCallback
(newValue?:any, oldValue?:any, extra?:any):void;
}
export interface AresCommandData
export interface ZriCommandData
{
/** 主命令名 */
cmdName:string;
......@@ -92,4 +92,4 @@ export interface AresCommandData
propName:string;
/** 表达式 */
exp:string;
}
\ No newline at end of file
}
......@@ -5,143 +5,134 @@
import {Watcher} from "./Watcher";
import {Dep} from "./Dep";
export class Mutator
{
// 记录数组中会造成数据更新的所有方法名
private static _arrMethods:string[] = [
"push",
"pop",
"unshift",
"shift",
"splice",
"sort",
"reverse"
];
export class Mutator {
// 记录数组中会造成数据更新的所有方法名
private static _arrMethods: string[] = [
"push",
"pop",
"unshift",
"shift",
"splice",
"sort",
"reverse"
];
/**
* 将用户传进来的数据“变异”成为具有截获数据变更能力的数据
* @param data 原始数据
* @returns {any} 变异后的数据
*/
public static mutate(data:any):any
{
// 如果是简单类型,则啥也不做
if(!data || typeof data != "object") return;
// 是个复杂类型对象,但是以前变异过了就不再重做一遍了
if(!data.__ares_mutated__)
{
// 针对每个内部变量都进行一次变异
for(var key in data)
{
Mutator.mutateObject(data, key, data[key]);
}
// 打一个标记表示已经变异过了
Object.defineProperty(data, "__ares_mutated__", {
value: true,
writable: false,
enumerable: false,
configurable: false
});
}
return data;
}
/**
* 将用户传进来的数据“变异”成为具有截获数据变更能力的数据
* @param data 原始数据
* @returns {any} 变异后的数据
*/
public static mutate(data: any): any {
// 如果是简单类型,则啥也不做
if (!data || typeof data != "object") return;
// 是个复杂类型对象,但是以前变异过了就不再重做一遍了
if (!data.__ares_mutated__) {
// 针对每个内部变量都进行一次变异
for (var key in data) {
Mutator.mutateProp(data, key, data[key]);
}
// 打一个标记表示已经变异过了
Object.defineProperty(data, "__ares_mutated__", {
value: true,
writable: false,
enumerable: false,
configurable: false
});
}
return data;
}
private static mutateObject(data:any, key:string, value:any):void
{
// 对每个复杂类型对象都要有一个对应的依赖列表
var dep:Dep = new Dep();
// 变异过程
Object.defineProperty(data, key, {
enumerable: true,
configurable: false,
get: ()=>{
// 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的
var watcher:Watcher = Watcher.updating;
if(watcher) dep.watch(watcher);
// 利用闭包保存原始值
return value;
},
set: v=>{
if(v == value) return;
value = v;
// 如果是数组就走专门的数组变异方法,否则递归变异对象
if(Array.isArray(v)) Mutator.mutateArray(v, dep);
else Mutator.mutate(v);
// 触发通知
dep.notify();
}
});
// 递归变异
Mutator.mutate(value);
}
private static mutateProp(data: any, key: string, value: any): void {
// 对每个复杂类型对象都要有一个对应的依赖列表
var dep: Dep = new Dep();
// 变异过程
Object.defineProperty(data, key, {
enumerable: true,
configurable: false,
get: () => {
// 如果Watcher.updating不是null,说明当前正在执行表达式,那么获取的变量自然是其需要依赖的
var watcher: Watcher = Watcher.updating;
if (watcher) dep.watch(watcher);
// 利用闭包保存原始值
return value;
},
set: v => {
if (v == value) return;
value = v;
// 如果是数组就走专门的数组变异方法,否则递归变异对象
if (Array.isArray(v)) Mutator.mutateArray(v, dep);
else Mutator.mutate(v);
// 触发通知
dep.notify();
}
});
if(Array.isArray(value)){
Mutator.mutateArray(value, dep);
}else{
// 递归变异
Mutator.mutate(value);
}
}
private static mutateArray(arr:any[], dep:Dep):void
{
// 变异当前数组
arr["__proto__"] = Mutator.defineReactiveArray(dep);
// 遍历当前数组,将内容对象全部变异
for(var i:number = 0, len:number = arr.length; i < len; i++)
{
Mutator.mutate(arr[i]);
}
}
private static mutateArray(arr: any[], dep: Dep): void {
// 变异当前数组
arr["__proto__"] = Mutator.defineReactiveArray(dep);
// 遍历当前数组,将内容对象全部变异
for (var i: number = 0, len: number = arr.length; i < len; i++) {
Mutator.mutate(arr[i]);
}
}
private static defineReactiveArray(dep:Dep):any[]
{
var proto:any[] = Array.prototype;
var result:any[] = Object.create(proto);
// 遍历所有方法,一个一个地变异
Mutator._arrMethods.forEach((method:string)=>{
// 利用闭包记录一个原始方法
var oriMethod:Function = proto[method];
// 开始变异
Object.defineProperty(result, method, {
value: function(...args:any[]):any
{
// 首先调用原始方法,获取返回值
var result:any = oriMethod.apply(this, args);
// 数组插入项
var inserted:any[];
switch(method)
{
case "push":
case "unshift":
inserted = args;
break
case "splice":
inserted = args.slice(2);
break
}
// 监视数组插入项,而不是重新监视整个数组
if(inserted && inserted.length)
{
Mutator.mutateArray(inserted, dep);
}
// 触发更新
dep.notify({method: args});
// 返回值
return result;
}
});
});
// 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异
Object.defineProperty(result, "$set", {
value: function(index:number, value:any):any
{
// 超出数组长度默认追加到最后
if(index >= this.length) index = this.length;
return this.splice(index, 1, value)[0];
}
});
// 提供替换数组移除的方法,因为直接移除的方式无法变异
Object.defineProperty(result, "$remove", {
value: function(item:any):any
{
var index = this.indexOf(item);
if(index > -1) return this.splice(index, 1);
return null;
}
});
return result;
}
private static defineReactiveArray(dep: Dep): any[] {
var proto: any[] = Array.prototype;
var result: any[] = Object.create(proto);
// 遍历所有方法,一个一个地变异
Mutator._arrMethods.forEach((method: string) => {
// 利用闭包记录一个原始方法
var oriMethod: Function = proto[method];
// 开始变异
Object.defineProperty(result, method, {
value: function (...args: any[]): any {
// 首先调用原始方法,获取返回值
var result: any = oriMethod.apply(this, args);
// 数组插入项
var inserted: any[];
switch (method) {
case "push":
case "unshift":
inserted = args;
break
case "splice":
inserted = args.slice(2);
break
}
// 监视数组插入项,而不是重新监视整个数组
if (inserted && inserted.length) {
Mutator.mutateArray(inserted, dep);
}
// 触发更新
dep.notify({method: args});
// 返回值
return result;
}
});
});
// 提供替换数组设置的方法,因为直接设置数组下标的方式无法变异
Object.defineProperty(result, "$set", {
value: function (index: number, value: any): any {
// 超出数组长度默认追加到最后
if (index >= this.length) index = this.length;
return this.splice(index, 1, value)[0];
}
});
// 提供替换数组移除的方法,因为直接移除的方式无法变异
Object.defineProperty(result, "$remove", {
value: function (item: any): any {
var index = this.indexOf(item);
if (index > -1) return this.splice(index, 1);
return null;
}
});
return result;
}
}
\ No newline at end of file
......@@ -6,27 +6,27 @@
* @param exp 表达式
* @returns {Function} 创建的方法
*/
export function createEvalFunc(exp:string):(scope:any)=>any
{
var func:(scope:any)=>any;
try
{
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any;
}
catch(err)
{
// 可能是某些版本的解释器不认识模板字符串,将模板字符串变成普通字符串
var sepStr:string = (exp.indexOf('"') < 0 ? '"' : "'");
// 将exp中的·替换为'
var reg:RegExp = /([^\\]?)`/g;
exp = exp.replace(reg, "$1" + sepStr);
// 将exp中${...}替换为" + ... + "的形式
reg = /\$\{(.*?)\}/g;
exp = exp.replace(reg, sepStr + "+($1)+" + sepStr);
// 重新生成方法并返回
func = Function("scope", "with(scope){return " + exp + "}") as (scope:any)=>any;
}
return func;
export function createEvalFunc(exp: string): (scope: any) => any {
var func: (scope: any) => any;
try {
func = Function("scope", "with(scope){return " + exp + "}") as (scope: any) => any;
} catch (err) {
// 可能是某些版本的解释器不认识模板字符串,将模板字符串变成普通字符串
var sepStr: string = (exp.indexOf('"') < 0 ? '"' : "'");
// 将exp中的·替换为'
var reg: RegExp = /([^\\]?)`/g;
exp = exp.replace(reg, "$1" + sepStr);
// 将exp中${...}替换为" + ... + "的形式
reg = /\$\{(.*?)\}/g;
exp = exp.replace(reg, sepStr + "+($1)+" + sepStr);
// 重新生成方法并返回
try {
func = Function("scope", "with(scope){return " + exp + "}") as (scope: any) => any;
}catch (e) {
console.error('非法的表达式:', exp);
}
}
return func;
}
/**
......@@ -35,9 +35,8 @@ export function createEvalFunc(exp:string):(scope:any)=>any
* @param scope 表达式的作用域
* @returns {any} 返回值
*/
export function evalExp(exp:string, scope:any):any
{
return createEvalFunc(exp)(scope);
export function evalExp(exp: string, scope: any): any {
return createEvalFunc(exp)(scope);
}
/**
......@@ -45,9 +44,8 @@ export function evalExp(exp:string, scope:any):any
* @param exp 表达式
* @returns {Function} 创建的方法
*/
export function createRunFunc(exp:string):(scope:any)=>void
{
return createEvalFunc("(function(){" + exp + "})()");
export function createRunFunc(exp: string): (scope: any) => void {
return createEvalFunc("(function(){" + exp + "})()");
}
/**
......@@ -55,7 +53,6 @@ export function createRunFunc(exp:string):(scope:any)=>void
* @param exp 表达式
* @param scope 表达式的作用域
*/
export function runExp(exp:string, scope:any):void
{
createRunFunc(exp)(scope);
export function runExp(exp: string, scope: any): void {
createRunFunc(exp)(scope);
}
\ No newline at end of file
import {IAres, IWatcher, WatcherCallback} from "./Interfaces";
import {IZri, IWatcher, WatcherCallback} from "./Interfaces";
import {createEvalFunc} from "./Utils";
/**
* Created by Raykid on 2016/12/22.
* 数据更新订阅者,当依赖的数据有更新时会触发callback通知外面
*/
export class Watcher implements IWatcher
{
/** 记录当前正在执行update方法的Watcher引用 */
public static updating:Watcher = null;
export class Watcher implements IWatcher {
/** 记录当前正在执行update方法的Watcher引用 */
public static updating: Watcher = null;
private static _uid:number = 0;
private static _uid: number = 0;
private _uid:number;
/** 获取Watcher的全局唯一ID */
public get uid():number
{
return this._uid;
}
private _uid: number;
/** 获取Watcher的全局唯一ID */
public get uid(): number {
return this._uid;
}
private _value:any;
private _value: any;
private _entity:IAres;
private _target:any;
private _exp:string;
private _scope:any;
private _expFunc:(scope:any)=>any;
private _callback:WatcherCallback;
private _entity: IZri;
private _target: any;
private _exp: string;
private _scope: any;
private _expFunc: (scope: any) => any;
private _callback: WatcherCallback;
private _disposed:boolean = false;
private _disposed: boolean = false;
public constructor(entity:IAres, target:any, exp:string, scope:any, callback:WatcherCallback)
{
// 记录entity
this._entity = entity;
// 生成一个全局唯一的ID
this._uid = Watcher._uid ++;
// 记录作用目标、表达式和作用域
this._target = target;
this._exp = exp;
this._scope = scope;
// 将表达式和作用域解析为一个Function
this._expFunc = createEvalFunc(exp);
// 记录回调函数
this._callback = callback;
// 进行首次更新
this.update();
}
public constructor(entity: IZri, target: any, exp: string, scope: any, callback: WatcherCallback) {
// 记录entity
this._entity = entity;
// 生成一个全局唯一的ID
this._uid = Watcher._uid++;
// 记录作用目标、表达式和作用域
this._target = target;
this._exp = exp;
this._scope = scope;
// 将表达式和作用域解析为一个Function
this._expFunc = createEvalFunc(exp);
// 记录回调函数
this._callback = callback;
// 进行首次更新
this.update();
}
/**
* 获取到表达式当前最新值
* @returns {any} 最新值
*/
public getValue():any
{
if(this._disposed) return null;
var value:any = null;
// 记录自身
Watcher.updating = this;
// 设置通用属性
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$root", {
configurable: true,
enumerable: false,
value: this._entity.compiler.root,
writable: false
});
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$target", {
configurable: true,
enumerable: false,
value: this._target,
writable: false
});
// 表达式求值
try
{
value = this._expFunc.call(this._scope, this._scope);
}
catch(err)
{
// 输出错误日志
console.warn("表达式求值错误\nerr: " + err.toString() + "\nexp:" + this._exp + ",scope:" + JSON.stringify(this._scope));
}
// 移除通用属性
delete this._scope["$root"];
delete this._scope["$target"];
// 移除自身记录
Watcher.updating = null;
return value;
}
/**
* 获取到表达式当前最新值
* @returns {any} 最新值
*/
public getValue(): any {
if (this._disposed) return null;
var value: any = null;
// 记录自身
Watcher.updating = this;
// 设置通用属性
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$root", {
configurable: true,
enumerable: false,
value: this._entity.compiler.root,
writable: false
});
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响context.scope
Object.defineProperty(this._scope, "$target", {
configurable: true,
enumerable: false,
value: this._target,
writable: false
});
// 表达式求值
try {
value = this._expFunc.call(this._scope, this._scope);
} catch (err) {
// 输出错误日志
console.warn("表达式求值错误\nerr: " + err.toString() + "\nexp:" + this._exp + ",scope:" + JSON.stringify(this._scope));
}
// 移除通用属性
delete this._scope["$root"];
delete this._scope["$target"];
// 移除自身记录
Watcher.updating = null;
return value;
}
/**
* 当依赖的数据有更新时调用该方法
* @param extra 可能的额外数据
*/
public update(extra?:any):void
{
if(this._disposed) return;
var value:any = this.getValue();
if(!Watcher.isEqual(value, this._value))
{
this._callback && this._callback(value, this._value, extra);
this._value = Watcher.deepCopy(value);
}
}
/** 销毁订阅者 */
public dispose():void
{
if(this._disposed) return;
this._value = null;
this._target = null;
this._exp = null;
this._scope = null;
this._expFunc = null;
this._callback = null;
this._disposed = true;
}
/**
* 当依赖的数据有更新时调用该方法
* @param extra 可能的额外数据
*/
public update(extra?: any): void {
if (this._disposed) return;
var value: any = this.getValue();
if (!Watcher.isEqual(value, this._value)) {
this._callback && this._callback(value, this._value, extra);
this._value = Watcher.deepCopy(value);
}
}
/**
* 是否相等,包括基础类型和对象/数组的对比
*/
private static isEqual(a:any, b:any):boolean
{
return (a == b || (
Watcher.isObject(a) && Watcher.isObject(b)
? JSON.stringify(a) == JSON.stringify(b)
: false
));
}
/** 销毁订阅者 */
public dispose(): void {
if (this._disposed) return;
this._value = null;
this._target = null;
this._exp = null;
this._scope = null;
this._expFunc = null;
this._callback = null;
this._disposed = true;
}
/**
* 是否为对象(包括数组、正则等)
*/
private static isObject(obj:any):boolean
{
return (obj && typeof obj == "object");
}
/**
* 是否相等,包括基础类型和对象/数组的对比
*/
private static isEqual(a: any, b: any): boolean {
return (a == b || (
Watcher.isObject(a) && Watcher.isObject(b)
? JSON.stringify(a) == JSON.stringify(b)
: false
));
}
/**
* 复制对象,若为对象则深度复制
*/
private static deepCopy(from:any):any
{
if (Watcher.isObject(from))
{
// 复杂类型对象,先字符串化,再对象化
return JSON.parse(JSON.stringify(from));
}
else
{
// 基本类型对象,直接返回之
return from;
}
}
/**
* 是否为对象(包括数组、正则等)
*/
private static isObject(obj: any): boolean {
return (obj && typeof obj == "object");
}
/**
* 复制对象,若为对象则深度复制
*/
private static deepCopy(from: any): any {
if (Watcher.isObject(from)) {
// 复杂类型对象,先字符串化,再对象化
return JSON.parse(JSON.stringify(from));
} else {
// 基本类型对象,直接返回之
return from;
}
}
}
\ No newline at end of file
/**
* Created by rockyl on 2020-03-19.
*/
import {IZri, Compiler, ZriOptions, IWatcher, WatcherCallback, ZriCommandData} from "./Interfaces";
import {Mutator} from "./Mutator";
import {Watcher} from "./Watcher";
import {CommandContext, Command, commands} from "./Commands"
export const defaultCmdRegExp:RegExp = /^(data\-)?z[\-_](\w+)([:\$](.+))?$/;
export class Zri implements IZri
{
private _data:any;
private _compiler:Compiler;
private _options:any;
/** 获取ViewModel */
public get data():any
{
return this._data;
}
/** 获取编译器 */
public get compiler():Compiler
{
return this._compiler;
}
public constructor(data:any, compiler:Compiler, options?:ZriOptions)
{
// 记录变异对象
this._data = Mutator.mutate(data);
this._compiler = compiler;
this._options = options;
// 初始化Compiler
this._compiler.init(this);
// 调用回调
if(this._options && this._options.inited)
{
this._options.inited.call(this._data, this);
}
}
public createWatcher(target:any, exp:string, scope:any, callback:WatcherCallback):IWatcher
{
return new Watcher(this, target, exp, scope, callback);
}
/**
* 解析表达式成为命令数据
* @param key 属性名,合法的属性名应以z-或z_开头,以:或$分隔主命令和子命令
* @param value 属性值,如果属性名合法则会被用来作为表达式的字符串
* @param cmdRegExp 可选,如果不传则使用默认的命令正则表达式解析命令
* @return {CommandData|null} 命令数据,如果不是命令则返回null
*/
public parseCommand(key:string, value:string, cmdRegExp?:RegExp):ZriCommandData
{
var result:RegExpExecArray = (cmdRegExp || defaultCmdRegExp).exec(key);
if(!result) return null;
// 取到key
var key:string = result[0];
// 取到命令名
var cmdName:string = result[2];
// 取到命令字符串
var exp:string = value;
// 取到子命令名
var subCmd:string = result[4] || "";
// 返回结构体
return {
cmdName: cmdName,
subCmd: subCmd,
propName: key,
exp: exp
};
}
/**
* 测试是否是通用命令
* @param data 命令数据
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public testCommand(data:ZriCommandData):boolean
{
// 非空判断
if(!data) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
return (cmd != null);
}
/**
* 执行通用命令,如果该表达式是通用命令则直接执行,否则什么都不做
* @param data 命令数据
* @param target 目标对象
* @param scope 变量作用域
* @return {boolean} 返回一个布尔值,表示该表达式是否是通用命令
*/
public execCommand(data:ZriCommandData, target:any, scope:any):boolean
{
// 非空判断
if(!data || !scope) return false;
// 取到通用命令
var cmd:Command = commands[data.cmdName];
// 没找到命令就返回false
if(!cmd) return false;
// 找到命令了,执行之
cmd({
target: target,
scope: scope,
entity: this,
data: data
});
return true;
}
}
/**
* Created by rockyl on 2020-03-19.
*/
import {DisplayObject} from "../../../2d/display/DisplayObject";
import {ZriCompiler} from "./ZriCompiler";
import {IWatcher, IZri, ZriCommandData} from "./Interfaces";
import {evalExp, runExp} from "./Utils";
import {Container} from "../../../2d/display/index";
export interface Command {
/**
* 执行命令
* @param context 命令上下文
*/
(context?: CommandContext): DisplayObject;
}
export interface CommandContext {
scope: any;
target: Container;
entity: IZri;
cmdData: ZriCommandData;
[name: string]: any;
}
export const commands: { [name: string]: Command } = {
prop: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
let target: DisplayObject = context.target;
context.entity.createWatcher(target, cmdData.exp, context.scope, (value: any) => {
if (cmdData.subCmd != "") {
target[cmdData.subCmd] = value;
} else {
for (let name in value) {
target[name] = value[name];
}
}
});
// 返回节点
return target;
},
on: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
if (cmdData.subCmd != "") {
let handler: Function = context.scope[cmdData.exp] || window[context.cmdData.exp];
if (typeof handler == "function") {
// 是函数名形式
context.target.addEventListener(cmdData.subCmd, function () {
handler.apply(this, arguments);
}, context.scope);
} else {
// 是方法执行或者表达式方式
context.target.addEventListener(cmdData.subCmd, (evt: Event) => {
// 创建一个临时的子域,用于保存参数
let scope: any = Object.create(context.scope);
scope.$event = evt;
scope.$target = context.target;
runExp(cmdData.exp, scope);
});
}
}
// 返回节点
return context.target;
},
if: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
// 记录一个是否编译过的flag
let compiled: boolean = false;
// 插入一个占位元素
let refNode: Container = new Container();
refNode.mouseChildren = refNode.mouseEnabled = false;
let parent: Container = context.target.parent;
let index: number = parent.getChildIndex(context.target);
parent.removeChildAt(index);
parent.addChildAt(refNode, index);
// 只有在条件为true时才启动编译
let watcher: IWatcher = context.entity.createWatcher(context.target, cmdData.exp, context.scope, (value: boolean) => {
// 如果refNode被从显示列表移除了,则表示该if指令要作废了
if (!refNode.parent && !context.target.parent) {
watcher.dispose();
return;
}
if (value == true) {
// 插入节点
if (!context.target.parent) {
let parent = refNode.parent;
let index: number = parent.getChildIndex(refNode);
parent.removeChild(refNode);
parent.addChildAt(context.target, index);
}
// 启动编译
if (!compiled) {
context.compiler.compile(context.target, context.scope);
compiled = true;
}
} else {
// 移除元素
if (context.target.parent) {
let parent = context.target.parent;
let index: number = parent.getChildIndex(context.target);
parent.removeChild(context.target);
parent.addChildAt(refNode, index);
}
}
});
// 返回节点
return context.target;
},
for: (context: CommandContext) => {
let cmdData: ZriCommandData = context.cmdData;
let options = evalExp(cmdData.subCmd, context.scope) || {};
let page: number = (options.page || Number.MAX_VALUE);
// 解析表达式
let reg: RegExp = /^\s*(\S+)\s+in\s+([\s\S]+?)\s*$/;
let res: RegExpExecArray = reg.exec(cmdData.exp);
if (!res) {
console.error("for命令表达式错误:" + cmdData.exp);
return;
}
let itemName: string = res[1];
let arrName: string = res[2];
// 生成一个容器替换原始模板
let index: number = context.target.parent.getChildIndex(context.target);
let parent: Container = new Container();
context.target.parent.addChildAt(parent, index);
context.target.parent.removeChild(context.target);
// 生成一个新的scope,要向其中添加属性
let forScope: any = Object.create(context.scope);
Object.defineProperty(forScope, "$forTarget", {
configurable: true,
enumerable: false,
value: context.target,
writable: false
});
// 如果有viewport命令,则将其转移至容器上
/*let viewportCmds:ZriCommandData[] = context.cmdDict["viewport"];
if(viewportCmds)
{
let viewportCmd:ZriCommandData = viewportCmds[0];
if(viewportCmd)
{
parent[viewportCmd.propName] = viewportCmd.exp;
delete context.target[viewportCmd.propName];
}
}*/
// 使用原始显示对象编译一次parent
context.compiler.compile(parent, forScope);
// 获取窗口显示范围
//let viewportHandler:ViewPortHandler = getViewportHandler(parent);
// 声明闭包数据
let isArray: boolean;
let curList: any[];
let curIndex: number;
let lastNode: DisplayObject;
// 添加订阅
let watcher: IWatcher = context.entity.createWatcher(context.target, arrName, forScope, (value: any) => {
// 如果refNode被从显示列表移除了,则表示该for指令要作废了
if (!parent.parent) {
watcher.dispose();
return;
}
// 清理原始显示
for (let i: number = parent.children.length - 1; i >= 0; i--) {
parent.removeChildAt(i).destroy();
}
// 如果是数字,构建一个数字列表
if (typeof value == "number") {
let temp: number[] = [];
for (let i: number = 0; i < value; i++) {
temp.push(i);
}
value = temp;
}
// 如果不是数组,而是字典,则转换为数组,方便中断遍历
isArray = (value instanceof Array);
let list: any[];
if (isArray) {
list = value;
} else {
list = [];
for (let key in value) {
list.push({
key: key,
value: value[key]
});
}
}
// 初始化数据
curList = list;
curIndex = 0;
lastNode = null;
for (let li = curList.length; curIndex < li; curIndex++) {
//渲染
// 拷贝一个target
let newNode: DisplayObject = context.target.clone(true, true);
// 添加到显示里
parent.addChild(newNode);
// 生成子域
let newScope: any = Object.create(forScope);
// 这里一定要用defineProperty将目标定义在当前节点上,否则会影响forScope
Object.defineProperty(newScope, "$index", {
configurable: true,
enumerable: false,
value: curIndex,
writable: false
});
// 如果是字典则额外注入一个$key
if (!isArray) {
Object.defineProperty(newScope, "$key", {
configurable: true,
enumerable: true,
value: curList[curIndex].key,
writable: false
});
}
// 注入上一个显示节点
Object.defineProperty(newScope, "$last", {
configurable: true,
enumerable: false,
value: lastNode,
writable: false
});
// 添加长度
Object.defineProperty(newScope, "$length", {
configurable: true,
enumerable: false,
value: curList.length,
writable: false
});
// 注入遍历名
Object.defineProperty(newScope, itemName, {
configurable: true,
enumerable: true,
value: (isArray ? curList[curIndex] : curList[curIndex].value),
writable: false
});
// 把单项数据注入到显示对象上
Object.defineProperty(newNode, "$data", {
configurable: true,
enumerable: false,
value: (isArray ? curList[curIndex] : curList[curIndex].value),
writable: false
});
// 开始编译新节点
context.compiler.compile(newNode, newScope);
// 赋值上一个节点
lastNode = newNode;
}
});
// 返回节点
return context.target;
}
};
\ No newline at end of file
This diff is collapsed.
/**
* Created by rockyl on 2020-03-02.
*/
import {Zri} from "./Zri";
import {Compiler, IZri, ZriOptions} from "./Interfaces";
import {ZriCompiler} from "./ZriCompiler";
import {Container} from "../../../2d/display/index";
import {safeEval} from "../../utils/utils";
/**
* 将数据模型和视图进行绑定
* @param store 数据
* @param view 视图
* @param options 一些额外参数
* @returns {IZri} 绑定实体对象
*/
export function bind(store: any, view: Container, options?: ZriOptions): IZri {
let compiler = new ZriCompiler(view);
let zri = new Zri(store, compiler, options);
compiler.debug();
return zri;
}
/**
* 通过配置生成数据
* @param exp
* @param computed
*/
export function createStore(exp, computed) {
let store = safeEval(exp) || {};
for (let {name, script} of computed) {
if (name && !store.hasOwnProperty(name)) {
let getterCode = `return function(){
${script}
}`;
Object.defineProperty(store, name, {
get: safeEval(getterCode),
})
}
}
return store;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment