初步架构完成
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
import { Util } from "../Common/util";
|
||||
import { Style } from "../Model/element";
|
||||
import { Shape } from "./shape";
|
||||
import { ShapeScheduler } from "./shapeScheduler";
|
||||
|
||||
|
||||
|
||||
export enum patchType {
|
||||
ADD,
|
||||
REMOVE,
|
||||
POSITION,
|
||||
PATH,
|
||||
ROTATION,
|
||||
SIZE,
|
||||
STYLE
|
||||
}
|
||||
|
||||
|
||||
export interface patchInfo {
|
||||
type: number;
|
||||
shape: Shape;
|
||||
}
|
||||
|
||||
|
||||
export class Reconciler {
|
||||
private shapeScheduler: ShapeScheduler;
|
||||
|
||||
constructor(shapeScheduler: ShapeScheduler) {
|
||||
this.shapeScheduler = shapeScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行图形样式对象的比较
|
||||
* @param oldStyle
|
||||
* @param newStyle
|
||||
*/
|
||||
reconcileStyle(oldStyle: Style, newStyle: Style): {name: string, old: any, new: any }[] {
|
||||
let styleName: {name: string, old: any, new: any }[] = [];
|
||||
|
||||
Object.keys(newStyle).map(prop => {
|
||||
if(newStyle[prop] !== oldStyle[prop]) {
|
||||
styleName.push({
|
||||
name: prop,
|
||||
old: oldStyle[prop],
|
||||
new: newStyle[prop]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return styleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 图形间的 differ
|
||||
* @param shape
|
||||
*/
|
||||
reconcileShape(shape: Shape) {
|
||||
let patchList: patchInfo[] = [];
|
||||
|
||||
if(shape.isDirty === false) return;
|
||||
|
||||
// 比较图形路径
|
||||
if(JSON.stringify(shape.prevShapeStatus) !== JSON.stringify(shape.shapeStatus.points)) {
|
||||
patchList.push({
|
||||
type: patchType.PATH,
|
||||
shape
|
||||
});
|
||||
}
|
||||
|
||||
// 比较图形坐标位置
|
||||
if(shape.prevShapeStatus.x !== shape.shapeStatus.x || shape.prevShapeStatus.y !== shape.shapeStatus.y) {
|
||||
patchList.push({
|
||||
type: patchType.POSITION,
|
||||
shape
|
||||
});
|
||||
}
|
||||
|
||||
// 比较旋转角度
|
||||
if(shape.prevShapeStatus.rotation !== shape.shapeStatus.rotation) {
|
||||
patchList.push({
|
||||
type: patchType.ROTATION,
|
||||
shape
|
||||
});
|
||||
}
|
||||
|
||||
// 比较尺寸
|
||||
if(shape.prevShapeStatus.width !== shape.shapeStatus.width || shape.prevShapeStatus.height !== shape.shapeStatus.height) {
|
||||
patchList.push({
|
||||
type: patchType.SIZE,
|
||||
shape
|
||||
});
|
||||
}
|
||||
|
||||
// 比较样式
|
||||
let style = this.reconcileStyle(shape.prevShapeStatus.style, shape.shapeStatus.style);
|
||||
if(style.length) {
|
||||
patchList.push({
|
||||
type: patchType.STYLE,
|
||||
shape
|
||||
});
|
||||
}
|
||||
|
||||
// 对变化进行更新
|
||||
this.patch(patchList);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param container
|
||||
* @param shapeList
|
||||
*/
|
||||
reconcileShapeList(container: { [key: string]: Shape[] }, shapeList: Shape[]) {
|
||||
let patchList: patchInfo[] = [];
|
||||
|
||||
for(let i = 0; i < shapeList.length; i++) {
|
||||
let shape = shapeList[i],
|
||||
name = shape.type;
|
||||
|
||||
// 若发现存在于新视图模型而不存在于旧视图模型的图形,则该图形都标记为 ADD
|
||||
if(container[name] === undefined) {
|
||||
patchList.push({
|
||||
type: patchType.ADD,
|
||||
shape
|
||||
});
|
||||
}
|
||||
else {
|
||||
let oldShape = container[name].find(item => item.id === shape.id);
|
||||
|
||||
// 若旧图形列表存在对应的图形,进行 shape 间 differ
|
||||
if(oldShape) {
|
||||
oldShape.isReconcilerVisited = true;
|
||||
this.reconcileShape(shape);
|
||||
}
|
||||
// 若发现存在于新视图模型而不存在于旧视图模型的图形,则该图形都标记为 ADD
|
||||
else {
|
||||
patchList.push({
|
||||
type: patchType.ADD,
|
||||
shape
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在旧视图容器中寻找未访问过的图形,表明该图形该图形需要移除
|
||||
Object.keys(container).forEach(key => {
|
||||
container[key].forEach(shape => {
|
||||
if(shape.isReconcilerVisited === false) {
|
||||
patchList.push({
|
||||
type: patchType.REMOVE,
|
||||
shape,
|
||||
});
|
||||
}
|
||||
|
||||
shape.isReconcilerVisited = false;
|
||||
});
|
||||
});
|
||||
|
||||
this.patch(patchList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对修改的视图进行补丁更新
|
||||
* @param patchList
|
||||
*/
|
||||
patch(patchList: patchInfo[]) {
|
||||
let patch: patchInfo,
|
||||
shape: Shape,
|
||||
i;
|
||||
|
||||
for(i = 0; i < patchList.length; i++) {
|
||||
patch = patchList[i];
|
||||
shape = patch.shape;
|
||||
|
||||
switch(patch.type) {
|
||||
case patchType.ADD: {
|
||||
this.shapeScheduler.appendShape(shape);
|
||||
this.shapeScheduler.emitAnimation(shape, 'append');
|
||||
break;
|
||||
}
|
||||
|
||||
case patchType.REMOVE: {
|
||||
this.shapeScheduler.removeShape(shape);
|
||||
this.shapeScheduler.emitAnimation(shape, 'remove');
|
||||
break;
|
||||
}
|
||||
|
||||
case patchType.PATH: {
|
||||
shape.prevShapeStatus.points = shape.shapeStatus.points;
|
||||
this.shapeScheduler.emitAnimation(shape, 'path');
|
||||
}
|
||||
|
||||
case patchType.POSITION: {
|
||||
shape.prevShapeStatus.x = shape.shapeStatus.x;
|
||||
shape.prevShapeStatus.y = shape.shapeStatus.y;
|
||||
this.shapeScheduler.emitAnimation(shape, 'position');
|
||||
break;
|
||||
}
|
||||
|
||||
case patchType.ROTATION: {
|
||||
shape.prevShapeStatus.rotation = shape.shapeStatus.rotation;
|
||||
this.shapeScheduler.emitAnimation(shape, 'rotation');
|
||||
break;
|
||||
}
|
||||
|
||||
case patchType.SIZE: {
|
||||
shape.prevShapeStatus.width = shape.shapeStatus.width;
|
||||
shape.prevShapeStatus.height = shape.shapeStatus.height;
|
||||
this.shapeScheduler.emitAnimation(shape, 'size');
|
||||
break;
|
||||
}
|
||||
|
||||
case patchType.STYLE: {
|
||||
shape.prevShapeStatus.style = Util.clone(shape.shapeStatus.style);
|
||||
this.shapeScheduler.emitAnimation(shape, 'style');
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export class Renderer {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
applyAnimation() {
|
||||
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -1,6 +1,6 @@
|
||||
import { Util } from "../Common/util";
|
||||
import { Element, Style } from "../Model/element";
|
||||
import { zrShape, ZrShapeConstructor } from "./shapeScheduler";
|
||||
import { Group, zrShape, ZrShapeConstructor } from "./shapeScheduler";
|
||||
|
||||
|
||||
export interface ShapeStatus {
|
||||
@@ -11,6 +11,7 @@ export interface ShapeStatus {
|
||||
width: number;
|
||||
height: number;
|
||||
content: string;
|
||||
points: [number, number][];
|
||||
style: Style;
|
||||
};
|
||||
|
||||
@@ -22,7 +23,8 @@ export class Shape {
|
||||
zrConstructor: ZrShapeConstructor = null;
|
||||
zrShape: zrShape = null;
|
||||
targetElement: Element = null;
|
||||
|
||||
parentGroup: Group = null;
|
||||
|
||||
shapeStatus: ShapeStatus = {
|
||||
x: 0, y: 0,
|
||||
rotation: 0,
|
||||
@@ -30,6 +32,7 @@ export class Shape {
|
||||
height: 0,
|
||||
zIndex: 1,
|
||||
content: '',
|
||||
points: [],
|
||||
style: {
|
||||
fill: '#000',
|
||||
text: '',
|
||||
@@ -43,12 +46,17 @@ export class Shape {
|
||||
}
|
||||
};
|
||||
|
||||
prevShapeStatus: ShapeStatus = null;
|
||||
isDirty: boolean = false;
|
||||
isReconcilerVisited: boolean = false;
|
||||
|
||||
constructor(id: string, zrConstructor: ZrShapeConstructor, element: Element) {
|
||||
this.id = id;
|
||||
this.type = Util.getClassName(zrConstructor);
|
||||
this.targetElement = element;
|
||||
this.zrConstructor = zrConstructor;
|
||||
this.zrShape = new zrConstructor();
|
||||
this.prevShapeStatus = Util.clone(this.shapeStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Element } from "../Model/element";
|
||||
|
||||
|
||||
export type zrShape = any;
|
||||
export type Group = any;
|
||||
export type ZrShapeConstructor = { new(): zrShape };
|
||||
|
||||
|
||||
@@ -14,6 +15,7 @@ export class ShapeScheduler {
|
||||
private shapeList: Shape[] = [];
|
||||
private shapeTable: { [key: string]: Shape[] } = {};
|
||||
|
||||
private parentGroupList: Group[] = [];
|
||||
private appendList: Shape[] = [];
|
||||
private removeList: Shape[] = [];
|
||||
|
||||
@@ -27,7 +29,7 @@ export class ShapeScheduler {
|
||||
* @param zrShapeConstructors
|
||||
* @param element
|
||||
*/
|
||||
createShape(id: string, zrShapeConstructors: ZrShapeConstructor, element: Element): Shape {
|
||||
public createShape(id: string, zrShapeConstructors: ZrShapeConstructor, element: Element): Shape {
|
||||
let shapeType = Util.getClassName(zrShapeConstructors),
|
||||
shape = this.getReuseShape(id, shapeType);
|
||||
|
||||
@@ -38,11 +40,28 @@ export class ShapeScheduler {
|
||||
return shape;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param shapes
|
||||
*/
|
||||
public packShapes(shapes: Shape[]){
|
||||
let group: Group = new zrender.Group(),
|
||||
shape: Shape;
|
||||
|
||||
for(let i = 0; i < shapes.length; i++) {
|
||||
shape = shapes[i];
|
||||
group.add(shape.zrShape);
|
||||
shape.parentGroup = group;
|
||||
}
|
||||
|
||||
this.parentGroupList.push(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个图形
|
||||
* @param shape
|
||||
*/
|
||||
private appendShape(shape: Shape) {
|
||||
public appendShape(shape: Shape) {
|
||||
let shapeType = shape.type;
|
||||
|
||||
if(this.shapeTable[shapeType] === undefined) {
|
||||
@@ -58,7 +77,7 @@ export class ShapeScheduler {
|
||||
* 移除一个图形
|
||||
* @param shape
|
||||
*/
|
||||
private removeShape(shape: Shape) {
|
||||
public removeShape(shape: Shape) {
|
||||
let shapeType = shape.type;
|
||||
|
||||
Util.removeFromList(this.shapeTable[shapeType], item => item.id === shape.id);
|
||||
@@ -71,6 +90,15 @@ export class ShapeScheduler {
|
||||
this.removeList.push(shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起一个动画请求
|
||||
* @param shape
|
||||
* @param animationType
|
||||
*/
|
||||
public emitAnimation(shape: Shape, animationType: string) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找可复用的图形
|
||||
* @param id
|
||||
|
||||
Reference in New Issue
Block a user